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?



Respuestas:


14
for f in **/*.cpp; do
  cat header_file $f > $f.new
  mv $f.new $f
done

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

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.


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

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

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

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.