Як додати заголовок ліцензії рекурсивно для всіх файлів .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.