Как рекурсивно добавить заголовок лицензии для всех файлов .h и .cpp в каталоге

19

Я пытаюсь добавить заголовок лицензии ко всем заголовочным файлам и исходным файлам в каталоге проекта, используя цикл for. Это не работает, есть ли другой подход sed?

Satyendra
источник

Ответы:

14
for f in **/*.cpp; do
  cat header_file $f > $f.new
  mv $f.new $f
done
Даниэль Серодио
источник
1
Следует отметить, что вам нужно включить globstarbash, чтобы это работало.
Крис Даун
И что вам нужно bash> 4.0 (например, Mac OS X и RedHat 5 все еще на 3.X)
Matteo
11

Это более или менее просто расширенный комментарий к ответу Даниэля Серодио . Я начал писать это как комментарий, но он быстро стал слишком большим ...

Для того чтобы bash glob был рекурсивным, требуется shopt -s globstar. Вы должны включить Globstar, иначе **не работает. Опция оболочки globstar была введена в версии 4 bash.

Чтобы избежать обработки каталога, такого как my.cpp/, используйте тест [[ -f $f ]]... Когда тест заключен в двойные квадратные скобки, переменные не должны заключаться в двойные кавычки.

Вы также можете рассмотреть возможность отсутствия подходящих файлов, используя шаблон shopt -s nullglob, который позволяет шаблонам, которые не соответствуют ни одному файлу, раскрываться в пустую строку, а не в себя.

Для того, чтобы обрабатывать несколько шаблонов, вы можете приковать шаблоны Глобы: **/*.cpp **/*.h, но , возможно , предпочтительно, когда вариант оболочка extglob находится на с помощью shopt -s extglob, вы можете использовать такие конструкции , такие , как , **/*.@(cpp|h)который позволяет избежать несколько проходов по файловой системе; один раз для каждого шаблона.

Если вы хотите, .filesчтобы вас включили, используйте и .*.cppт. Д. Или используйтеshopt -s dotglob

Чтобы безопасно обрабатывать изменения файла, который передается по конвейеру, используйте spongefrom package moreutils(это избавляет вас от необходимости создавать собственный временный файл)


printf "// The License\n\n" > /tmp/$USER-license

shopt -s globstar nullglob extglob
for f in **/*.@(cpp|h) ;do
  [[ -f $f ]] && cat "/tmp/$USER-license" "$f" | sponge "$f"
done
Peter.O
источник
Гораздо более полный и информативный ответ, чем другой, +1
n0pe
+1, но [[может изящно обработать ноль $f.
энзотиб
@enzotib. Благодарю. Я не уверен, откуда у меня эта идея. Это должно было быть из того, как работает одна квадратная скобка (не) ... например, unset x; [ -f $x ] && echo exists отчеты "существуют" ... (исправлено)
Peter.O
Начиная с версии 4 Баш не мейнстрим пока я бы подставить **/*.@(cpp|h)с$( find . -name "*.h" -name "*.cpp")
Маттео
3

Спасибо @fred, @maxmackie, @enzotib.

Можете ли вы проверить процедуру, которой я следовал.

#!/bin/sh
# script to copy the headers to all the source files and header files
for f in *.cpp; do
  if (grep Copyright $f);then 
    echo "No need to copy the License Header to $f"
  else
    cat license.txt $f > $f.new
    mv $f.new $f
    echo "License Header copied to $f"
  fi 
done   

в противном случае заголовок лицензии будет скопирован несколько раз.

Пожалуйста, предложите мне шаблон для просмотра всех заголовков и источников в каталоге проекта и его подкаталогах.

Я не мог полностью понять, что предложил @fred.

Satyendra
источник
В целом, ваш код выглядит хорошо. Я бы более конкретно определил точное местоположение «Copyright», например. укажите номер строки и положение в этой строке. Вы можете предотвратить чтение файла целиком, выйдя на строку, где вы ожидаете найти «Авторское право» ... например. targln=2; findln=$(sed -rne $targln'{\|// Copyright|=;q}' "$f"); if ((findln==targln));then... но, конечно, помимо всего прочего, сначала тщательно проверь это ... PS. Разумеется, здесь, в Unix & Linux, можно публиковать такие дополнения в своем первоначальном вопросе, а не в качестве ответа ...
Peter.O
1
Несколько советов: уберите круглые скобки grep, добавьте -qопцию к grep. Всегда добавляйте двойные кавычки $f.
энзотиб
1
Цитаты очень важны, в противном случае вас, скорее всего, укусит разделение слов. Как правило, заключайте в кавычки каждое расширение, если только вы не знаете, что расщепление слов или другая интерпретация не будут выполняться оболочкой.
Крис Даун
3

Вы можете сделать это с помощью exили, edесли хотите, (вы не должны делать это так, sedкак вы просили, sedпредназначен для редактирования потоков, -iэто плохая идея по разным причинам):

shopt -s globstar

for _file in **/*.@(cpp|h); do
    ed -s "${_file}" << EOF
0a
/* This file is licensed under the foo license.
   All copyright strictly enforced by the copyright monster. */
.
w
EOF
    done
Крис Даун
источник
Почему sed -iплохая идея?
Даниэль Серодио
@DanielSerodio По умолчанию sed -iломает символические и жесткие ссылки, что приводит к неожиданному поведению. В лучшем случае это не интуитивно понятно, в худшем - активно вредно.
Крис Даун
2

Если у вас есть header_fileжелаемое содержимое:

find -name '*.cpp' -exec bash -c 'cat header_file \{} > \{}.new; mv \{}.new  \{}' \;
find -name '*.h' -exec bash -c 'cat header_file \{} > \{}.new; mv \{}.new  \{}' \;
albfan
источник
1
#!/bin/bash

for i in `find . -name '*.[m|h]'` # or whatever other pattern...
do
  echo $i
  if ! grep -q Copyright $i
  then
    cat copyright.txt $i >$i.new && mv $i.new $i
  fi
done
enter code here
PokerIncome.com
источник
0

Блог Герхарда Гаппмайера - Как рекурсивно заменить заголовки файлов исходных файлов

К сообщению в блоге прикреплен tar.gzфайл, содержащий необходимые файлы.

В нем есть header.templateфайл, в котором вы можете написать собственный комментарий, он может занимать несколько строк.

У него есть remove_header.awkскрипт, который заменяет существующие заголовки новым заголовком.

Чтобы запустить его:

find . -name "*.h" -exec ~/rh/replace_header.sh {} \;
neoneye
источник