Как добавить содержимое конкретного текстового файла в каждый текстовый файл в каталоге и его подкаталогах?

Мне не нравится загромождать файлы исходного кода комментариями о лицензировании / атрибуции, но иногда это требование. Поэтому, имея десятки файлов исходного кода (организованных в дереве подкаталогов), мне нужно добавить один и тот же многострочный комментарий к началу каждого из них.

Я подозреваю, что это очень простая задача, связанная со стандартными инструментами командной строки GNU / Linux, хотя я едва ли умею их серьезно использовать, поэтому прошу прощения и прошу вас о помощи.

Мне нужно заменить каждый theTargetFile.txt в ./*.txt (в том числе в подкаталогах рекурсивно) с чем-то вроде cat theCommonComment.txt theTargetFile.txt .

Я также предпочел бы исключать файлы, устанавливающие конкретную более конкретную маску, например, рассматривать все *.txt но оставлять *.DontTouch.txt неповрежденным.

Я думаю, что самая сложная часть того, что мне действительно нужно, – это заклинание с фантастическим find которое будет проходить через подкаталоги, включая файлы *.txt и исключать файлы *.DontTouch.txt .

  • Как изменить время BIRTH файла BSD (aka btime)?
  • Быстрый способ удалить строку из чрезвычайно большого файла
  • Какой может быть вариант изменения измененного времени файла в будущем?
  • Ищете ресурсы: например, C doc для чтения файлов и их атрибутов? (В Linux)
  • Как восстановить рекурсивный «chmod -x» в моей домашней папке
  • Есть ли надежный способ кэширования содержимого usb на локальном hd?
  • Стандартные дескрипторы файла ввода-вывода
  • Как сортировать файлы отдельно без слияния?
  • 6 Solutions collect form web for “Как добавить содержимое конкретного текстового файла в каждый текстовый файл в каталоге и его подкаталогах?”

    Самый прямой способ, который я вижу, это сделать с GNU find , bash и утилитой sponge от moreutils :

     find dir/with/files -name '*.txt' ! -name '*.DontTouch.txt' -print0 | while IFS= read -rd '' file; do echo 'cat path/to/theCommonComment.txt "$file" | sponge "$file"' done 

    В его нынешнем виде это будет просто печатать команды cat / sponge фактически ничего не делая. Как только вы убедитесь, что у вас есть то, что вы хотите, вы можете удалить эхо и одиночные кавычки, окружающие команду.

    Без использования опции sponge или -print0 для поиска, которая может быть недоступна для всех систем:

     find dir/with/files -name '*.txt' ! -name '*.DontTouch.txt' -exec sh ' for file; do tempfile=$(mktemp) cat path/to/theCommonComment.txt "$file" >"$tempfile" mv "$tempfile" "$file" done ' sh {} + 

    Нет простого способа остановить это, просто напечатайте, что он будет делать, поэтому будьте осторожны. Одна вещь, на которую следует обратить внимание – убедитесь, что ваш файл theCommonComment.txt не находится в каталоге, в котором вы выполняете рекурсивную операцию (или, по крайней мере, убедитесь, что он исключен из поиска), иначе вы получите два заголовки в некоторых файлах.

    Обновить

    Последняя мысль заключается в том, что вы можете проверить, добавлен ли заголовок в файл. Это может быть полезно, если вы добавляете новые файлы и должны снова запустить команду. Он также сталкивается с проблемой наличия файла theCommonComment.txt в пути поиска. Эти два решения станут:

     comment_file=path/to/theCommonComment.txt size=$(wc -c "$comment_file") find dir/with/files -name '*.txt' ! -name '*.DontTouch.txt' -print0 | while IFS= read -rd '' file; do if [ cmp -n "$size" $comment_file" "$file" ]; do echo 'cat "$comment_file" "$file" | sponge "$file"' fi done 
     export comment_file=path/to/theCommonComment.txt export size=$(wc -c "$comment_file") find dir/with/files -name '*.txt' ! -name '*.DontTouch.txt' -exec sh ' for file; do if [ cmp -n "$size" $comment_file" "$file" ]; do tempfile=$(mktemp) cat "$comment_file" "$file" >"$tempfile" mv "$tempfile" "$file" fi done ' sh {} + 

    На GNU / что угодно, чтобы вставить _after_ первую строку:

     find -name '*.txt' ! -name '*thispattern*' ! -name '*thatpattern*' \ -exec sed -si '1r TheLicense.txt' '{}' + 

    для вставки файла раньше, простейший несколько медленнее и немного kludgier:

     find -name '*.txt' ! -name '*thispattern*' ! -name '*thatpattern*' \ -exec sed -si '1{h;s,.*,cat TheLicense.txt,ep;g}' '{}' + 

    С zsh :

     zmodload zsh/mapfile setopt extendedglob # best in ~/.zshrc for f (Dir/**/(^*DontTouch).txt(N.)) mapfile[$f]=$mapfile[theCommonComment.txt]$mapfile[$f] 

    Я бы создал файл как dummy с содержимым, которое вы хотите заменить. Такой dummy файл будет выглядеть ниже.

     <?php /** * * Copyright (C) MyCompany, Ltd. - All Rights Reserved * Unauthorized copying of this file, via any medium is strictly prohibited * Proprietary and Confidential * * */ 

    После этого я выполнил бы следующий скрипт.

     for f in ./*; do sed -i '/<?php/{ s/<?php//g r dummy }' $f done 

    Я заменяю <?php пробелами и заменяю его содержимым из dummy файла.

    Конечно, вы можете изменить приведенный выше код в соответствии с вашими требованиями.

    Однако есть гораздо более сложный способ сделать это.

     for f in *; do echo "whatever" > tmpfile cat $f >> tmpfile mv tmpfile $f done 

    Вышеприведенный ответ был взят отсюда . Вы в основном помещаете содержимое сначала в tmp-файл, а затем добавляете исходное содержимое в tmp-файл. Теперь, после этого, вы переименуете tmpfile обратно в исходное имя файла.

    Это решение использует bash, find, tac и sed.

    Скопируйте следующий скрипт в файл и сделайте исполняемый файл: chmod +x script

    Затем используйте следующее:

     ./script <DIR> <HEADERFILE> 

    где

     <DIR> The directory containing files ( or directory containing files..) <HEADERFILE> The file to add on top of each file 

    Это сценарий:

     #!/bin/bash # inset a file content at the beginning of each matching files DIR=$1 HEADER_FILE=$2 #the matching files will be ignored IGNORE_FILE="*.DontTouch.txt" insertHeader(){ local targetfile=$1 local headerfile=$2 echo "$targetfile" while read line do # echo $line sed -i "$targetfile" -e "1i$line\ " done< <(tac "$headerfile") } export -f insertHeader find "$DIR" -type f -name "*.txt" ! -name "$IGNORE_FILE" -exec bash -c "insertHeader {} $HEADER_FILE" \; 

    Это решение воспользуется командами find и xargs:

     find . -name "*.txt" -a ! -name "*.DontTouch.txt" -print | xargs -n 1 cat theCommonComment.txt 
    Linux и Unix - лучшая ОС в мире.