Як додати заголовок ліцензії рекурсивно для всіх файлів .h та .cpp у каталозі


19

Я намагаюся додати заголовок ліцензії до всіх файлів заголовків та вихідних файлів у каталозі проекту, використовуючи цикл for. Це не працює, чи є якийсь інший підхід sed?


1
Дуже схожий випадок: unix.stackexchange.com/questions/20577 / ...
РВМ

Відповіді:


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)
Маттео

11

Це більш-менш просто розширений коментар до відповіді Даніеля Серодіо . Я почав писати це як коментар, але він швидко став занадто великим ...

Щоб глобус-баш був рекурсивним, це потрібно 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

Щоб безпечно обробити зміни файлу, який передається в трубопровід, використовуйте spongeпакет 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

Набагато
повніша

+1, але [[може витончено обробити нуль $f.
enzotib

@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.


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

1
Деякі поради: видаліть круглі дужки навколо grep, додайте -qпараметр до grep. Завжди додайте подвійні лапки $f.
enzotib

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  \{}' \;

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

0

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

До публікації блогу додається tar.gzфайл, що містить необхідні файли.

У ньому є header.templateфайл, куди можна написати спеціальний коментар, він може охоплювати кілька рядків.

У ньому є remove_header.awkсценарій, який замінює існуючі заголовки новим заголовком.

Для того, щоб запустити його:

find . -name "*.h" -exec ~/rh/replace_header.sh {} \;
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.