Como anexar recursivamente um cabeçalho de licença a todos os arquivos .h e .cpp em um diretório

19

Estou tentando adicionar um cabeçalho de licença a todos os arquivos de cabeçalho e arquivos de origem em um diretório de projeto usando um loop for. Isso não está funcionando, existe alguma outra abordagem usando sed?

Satyendra
fonte

Respostas:

14
for f in **/*.cpp; do
  cat header_file $f > $f.new
  mv $f.new $f
done
Daniel Serodio
fonte
1
Deve-se mencionar que você precisa ativar o globstarbash para que isso funcione.
Chris Baixo
E que você precisa do bash> 4.0 (por exemplo, o Mac OS X e o RedHat 5 ainda estão no 3.X)
Matteo
11

Este é mais ou menos apenas um comentário estendido sobre a resposta de Daniel Serodio . Comecei a escrever como um comentário, mas rapidamente cresceu muito ...

Para que um bash glob seja recursivo, é necessário shopt -s globstar. Você deve ativar o globstar, caso contrário **não funcionará. A opção de shell globstar foi introduzida na versão 4 do bash.

Para evitar o processamento de um diretório como my.cpp/, use o teste [[ -f $f ]]... Quando o teste está entre colchetes duplos, as variáveis ​​não precisam ser citadas duas vezes.

Você também pode considerar a possibilidade de não haver arquivos correspondentes usando shopt -s nullglob, o que permite que os padrões que não correspondem a arquivos sejam expandidos para uma cadeia nula, e não para eles próprios.

Para lidar com múltiplos padrões, você pode encadear os padrões glob: **/*.cpp **/*.h, mas talvez de preferência, quando a opção shell extglob é na via shopt -s extglob, você pode usar tais construções, como **/*.@(cpp|h)o que evita várias passagens sobre o sistema de arquivos; uma vez para cada padrão.

Se você deseja .filesser incluído, use .*.cppetc ou useshopt -s dotglob

Para manipular com segurança a modificação de um arquivo que está sendo canalizado, use spongefrom package moreutils(economiza a necessidade de criar seu próprio arquivo temporário)


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
fonte
Resposta muito mais completa e informativa do que a outra, +1
n0pe
+1, mas [[pode lidar normalmente com um nulo $f.
enzotib 14/09/11
@enzotib. obrigado. Não tenho certeza de onde tive essa ideia. Deve ter sido de como funciona de colchetes simples (não) ... por exemplo, unset x; [ -f $x ] && echo exists relatórios "existe" ... (fixo)
Peter.O
Como a versão 4 do bash ainda não é mainstream, eu substitui o **/*.@(cpp|h)por$( find . -name "*.h" -name "*.cpp")
Matteo
3

Obrigado @fred, @maxmackie, @enzotib.

Você pode, por favor, verificar o procedimento que segui.

#!/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   

caso contrário, o cabeçalho da licença será copiado para vários números de vezes.

Por favor, sugira-me um padrão para percorrer todos os cabeçalhos e fontes no diretório e subdiretórios do projeto.

Não consegui entender completamente o que o @fred sugeriu.

Satyendra
fonte
Em geral, seu código parece bem. Eu seria mais específico sobre como identificar a localização exata de "Copyright", por exemplo. especifique o número e a posição da linha nessa linha. Você pode impedir a leitura sediada do arquivo inteiro saindo da linha em que espera encontrar "Copyright" ... por exemplo. targln=2; findln=$(sed -rne $targln'{\|// Copyright|=;q}' "$f"); if ((findln==targln));then... mas, é claro, acima e além de tudo o mais, teste-o primeiro ... PS. É par para o curso aqui no Unix e Linux para postar esses extras na sua pergunta original, não como uma resposta ...
Peter.O
1
Alguns conselhos: remova os parênteses grep, adicione a -qopção a grep. Sempre adicione aspas duplas $f.
enzotib 15/09/11
1
As cotações são vitais; caso contrário, você provavelmente será mordido pela divisão de palavras. Como regra básica, cite cada expansão, a menos que você saiba que a divisão de palavras ou outra interpretação não será executada pelo shell.
Chris Baixo
3

Você pode fazer isso com exou edse preferir (não o faça sedconforme solicitado), sedfoi projetado para editar fluxos, -ié uma má ideia por vários motivos):

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
Chris Down
fonte
Por que é sed -iuma má ideia?
Daniel Serodio
@DanielSerodio Por padrão, sed -iquebra links simbólicos e hardlinks, resultando em comportamento inesperado. Na melhor das hipóteses, não é intuitivo; na pior, é ativamente prejudicial.
Chris Baixo
2

Se você tiver um header_filecom o conteúdo desejado:

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
fonte
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
fonte