Cómo anteponer un encabezado de licencia de forma recursiva para todos los archivos .h y .cpp en un directorio

19

Estoy tratando de agregar un encabezado de licencia a todos los archivos de encabezado y archivos de origen en un directorio de proyecto usando un bucle for. Esto no está funcionando, ¿hay algún otro enfoque que esté usando sed?

Satyendra
fuente

Respuestas:

14
for f in **/*.cpp; do
  cat header_file $f > $f.new
  mv $f.new $f
done
Daniel Serodio
fuente
1
Debe mencionarse que necesita activar globstarbash para que esto funcione.
Chris Down
Y que necesita bash> 4.0 (por ejemplo, Mac OS X y RedHat 5 todavía están en 3.X)
Matteo
11

Esto es más o menos un comentario extenso sobre la respuesta de Daniel Serodio '' . Comencé a escribirlo como un comentario, pero rápidamente creció demasiado ...

Para que un bash glob sea recursivo, se requiere shopt -s globstar. Debes habilitar globstar, de lo contrario **no funciona. La opción de shell globstar se introdujo en la versión 4 de bash.

Para evitar el procesamiento de un directorio como my.cpp/, use la prueba [[ -f $f ]]... Cuando la prueba está entre corchetes dobles, no es necesario que se doblen las variables.

También puede considerar la posibilidad de que no haya archivos coincidentes mediante el uso shopt -s nullglob, que permite que los patrones que no coinciden con ningún archivo se expandan a una cadena nula, en lugar de a sí mismos.

Para manejar múltiples patrones, puede encadenar los patrones glob: **/*.cpp **/*.hpero quizás de manera preferible, cuando la opción de shell extglob está activada a través de shopt -s extglob, puede usar construcciones tales como las **/*.@(cpp|h)que evitan múltiples pases sobre el sistema de archivos; una vez para cada patrón.

Si desea .filesser incluido, use .*.cppetc., o useshopt -s dotglob

Para manejar de manera segura la modificación de un archivo que se está canalizando, use spongedesde el paquete moreutils(le ahorra la necesidad de crear su propio archivo temporal)


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
fuente
Respuesta mucho más completa e informativa que la otra, +1
n0pe
+1, pero [[puede manejar con gracia un nulo $f.
enzotib
@enzotib. Gracias. No estoy seguro de dónde se me ocurrió esa idea. Debe haber sido de cómo funciona el corchete único (no) ... por ejemplo, los unset x; [ -f $x ] && echo exists informes "existen" ... (arreglado)
Peter.O
Dado que la versión 4 de bash aún no es mainstream, la sustituiría **/*.@(cpp|h)por$( find . -name "*.h" -name "*.cpp")
Matteo
3

Gracias @fred, @maxmackie, @enzotib.

¿Puede por favor verificar el procedimiento que he seguido?

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

de lo contrario, el encabezado de la licencia se copiará varias veces.

Sugiérame un patrón para recorrer todos los encabezados y fuentes en el directorio y subdirectorios del proyecto.

No pude entender completamente lo que @fred ha sugerido.

Satyendra
fuente
En general, su código se ve bien. Sería más específico sobre la identificación de la ubicación exacta de "Copyright", por ejemplo. especifique el número de línea y la posición en esa línea. Puede evitar que sed lea el archivo completo al salir de la línea donde espera encontrar "Copyright" ... por ejemplo. targln=2; findln=$(sed -rne $targln'{\|// Copyright|=;q}' "$f"); if ((findln==targln));then... pero, por supuesto, más allá de todo lo demás, pruébelo primero ... PD. Es normal que el curso aquí en Unix y Linux publique tales extras en su pregunta original, no como una respuesta ...
Peter.O
1
Algunos consejos: elimine los paréntesis grep, agregue la -qopción a grep. Siempre agregue comillas dobles $f.
enzotib
1
Las citas son vitales, de lo contrario, probablemente te muerda la división de palabras. Como regla básica, cite cada expansión a menos que sepa que el shell no realizará la división de palabras u otra interpretación.
Chris Down
3

Puede hacerlo con exo edsi lo prefiere (no debe hacerlo con sedlo que solicitó, sedestá diseñado para editar transmisiones, -ies una mala idea por varias razones):

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
fuente
¿Por qué es sed -iuna mala idea?
Daniel Serodio
@DanielSerodio Por defecto, sed -irompe enlaces simbólicos y enlaces duros, lo que resulta en un comportamiento inesperado. En el mejor de los casos, no es intuitivo, en el peor es activamente dañino.
Chris Down
2

Si tiene un header_filecontenido deseado:

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