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

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

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

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

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

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

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 
  • Поиск файлов в порядке времени
  • Как использовать wget со списком URL-адресов и их соответствующими выходными файлами?
  • Как разделить конфигурацию `rc.lua` Awesome на несколько файлов?
  • Как увеличить количество inodes в файловой системе ext4?
  • Как rsync файлы с номером имени файла больше, чем число?
  • В чем разница между двоичным файлом и библиотекой?
  • Переместить файл на основе его содержимого
  • Как извлечь определенное значение из файла журнала и перенести его в другой файл
  • Сжатие папки, но не сжимать определенные типы файлов, а включать их в файл gz
  • Обратная сторона `tree` - восстанавливает структуру файлов и каталогов из содержимого текстового файла?
  • Сценарий Bash для исправления имен файлов
  • Как перемещать все файлы (исключая подкаталоги) из одного каталога в другой?
  • Linux и Unix - лучшая ОС в мире.