Comment ajouter un en-tête de licence de manière récursive pour tous les fichiers .h et .cpp dans un répertoire


19

J'essaie d'ajouter un en-tête de licence à tous les fichiers d'en-tête et fichiers source dans un répertoire de projet à l'aide d'une boucle for. Cela ne fonctionne pas, existe-t-il une autre approche sed?



Réponses:


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

1
Il convient de mentionner que vous devez activer globstaren bash pour que cela fonctionne.
Chris Down du

Et que vous avez besoin de bash> 4.0 (par exemple, Mac OS X et RedHat 5 sont toujours sur 3.X)
Matteo

11

Il s'agit plus ou moins d'un long commentaire sur la réponse de Daniel Serodio . J'ai commencé à l'écrire comme un commentaire, mais il est rapidement devenu trop grand ...

Pour qu'un glob bash soit récursif, il faut shopt -s globstar. Vous devez activer globstar, sinon **cela ne fonctionne pas. L'option shell globstar a été introduite dans la version 4 de bash.

Pour éviter de traiter un répertoire tel que my.cpp/, utilisez le test [[ -f $f ]]... Lorsque le test est entre crochets doubles, les variables n'ont pas besoin d'être mises entre guillemets.

Vous pouvez également envisager la possibilité qu'il n'y ait aucun fichier correspondant en utilisant shopt -s nullglob, ce qui permet aux modèles qui ne correspondent à aucun fichier de se développer en une chaîne nulle, plutôt qu'eux-mêmes.

Pour gérer plusieurs modèles, vous pouvez enchaîner les modèles glob: **/*.cpp **/*.h, mais peut - être de préférence, lorsque l'option shell extglob est sur via shopt -s extglob, vous pouvez utiliser ces constructions telles que ce **/*.@(cpp|h)qui évite plusieurs passages sur le système de fichiers; une fois pour chaque motif.

Si vous voulez .filesêtre inclus, utilisez .*.cppetc, ou utilisezshopt -s dotglob

Pour gérer en toute sécurité la modification d'un fichier en cours de piping, utilisez spongefrom package moreutils(cela vous évite de créer votre propre fichier temporaire)


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

Réponse beaucoup plus complète et informative que l'autre, +1
n0pe

+1, mais [[peut gracieusement gérer un null $f.
enzotib

@enzotib. Merci. Je ne suis pas sûr d'avoir eu cette idée. Cela doit unset x; [ -f $x ] && echo exists
provenir

Étant donné que la version 4 de bash n'est pas encore courante, je remplacerais la **/*.@(cpp|h)par$( find . -name "*.h" -name "*.cpp")
Matteo

3

Merci @fred, @maxmackie, @enzotib.

Pouvez-vous s'il vous plaît vérifier la procédure que j'ai suivie.

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

sinon l'en-tête de licence sera copié plusieurs fois.

Veuillez me suggérer un modèle pour parcourir tous les en-têtes et sources du répertoire et des sous-répertoires du projet.

Je n'ai pas pu comprendre pleinement ce que @fred a suggéré.


En général, votre code semble correct. Je serais plus précis sur l'identification de l'emplacement exact de "Copyright", par exemple. spécifiez le numéro et la position de la ligne sur cette ligne. Vous pouvez empêcher sed de lire l'intégralité du fichier en quittant la ligne où vous vous attendez à trouver "Copyright" ... par exemple. targln=2; findln=$(sed -rne $targln'{\|// Copyright|=;q}' "$f"); if ((findln==targln));then... mais, bien sûr, au-delà de tout le reste, testez-le soigneusement en premier ... PS. C'est normal pour le cours ici à Unix et Linux de publier de tels extras dans votre question d'origine, pas comme réponse ...
Peter.O

1
Quelques conseils: supprimez les parenthèses autour grep, ajoutez l' -qoption à grep. Ajoutez toujours des guillemets $f.
enzotib

1
Les citations sont vitales, sinon vous serez probablement mordu par le fractionnement des mots. En règle générale, citez chaque expansion sauf si vous savez que le fractionnement de mots ou toute autre interprétation ne sera pas effectué par le shell.
Chris Down du

3

Vous pouvez le faire avec exou edsi vous préférez (vous ne devriez pas le faire avec sedcomme vous l'avez demandé, sedest conçu pour modifier les flux, -iest une mauvaise idée pour diverses raisons):

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

Pourquoi est-ce sed -iune mauvaise idée?
Daniel Serodio

@DanielSerodio Par défaut, sed -irompt les liens symboliques et les liens physiques, ce qui entraîne un comportement inattendu. Au mieux, il n'est pas intuitif, au pire, il est activement nocif.
Chris Down

2

Si vous en avez un header_fileavec le contenu souhaité:

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

Blog de Gerhard Gappmeier - Comment remplacer récursivement les en-têtes de fichiers des fichiers source

Le billet de blog a joint un tar.gzfichier contenant les fichiers nécessaires.

Il a un header.templatefichier, où vous pouvez écrire un commentaire personnalisé, il peut s'étendre sur plusieurs lignes.

Il a un remove_header.awkscript qui remplace les en-têtes existants par le nouvel en-tête.

Pour l'exécuter:

find . -name "*.h" -exec ~/rh/replace_header.sh {} \;
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.