So stellen Sie einen Lizenzheader rekursiv für alle .h- und .cpp-Dateien in einem Verzeichnis voran

19

Ich versuche, mit einer for-Schleife einen Lizenzheader zu allen Header- und Quelldateien in einem Projektverzeichnis hinzuzufügen. Das funktioniert nicht. Gibt es einen anderen Ansatz sed?

Satyendra
quelle

Antworten:

14
for f in **/*.cpp; do
  cat header_file $f > $f.new
  mv $f.new $f
done
Daniel Serodio
quelle
1
Es sollte erwähnt werden, dass Sie globstarBash einschalten müssen, damit dies funktioniert.
Chris Down
Und dass du bash> 4.0 brauchst (zB Mac OS X und RedHat 5 sind immer noch auf 3.X)
Matteo
11

Dies ist mehr oder weniger nur ein ausführlicher Kommentar zur Antwort von Daniel Serodio . Ich fing an, es als Kommentar zu schreiben, aber es wurde schnell zu groß ...

Damit ein Bash-Glob rekursiv ist, ist es erforderlich shopt -s globstar. Sie müssen globstar aktivieren, sonst **funktioniert es nicht. Die Globstar-Shell-Option wurde in Version 4 von Bash eingeführt.

my.cpp/Verwenden Sie den Test, um zu vermeiden, dass ein Verzeichnis wie [[ -f $f ]]... verarbeitet wird. Wenn der Test in doppelten eckigen Klammern steht, müssen Variablen nicht in doppelte Anführungszeichen gesetzt werden.

Sie können auch die Möglichkeit in Betracht ziehen, dass keine übereinstimmenden Dateien vorhanden sind, indem Sie verwenden shopt -s nullglob, wodurch Muster, die nicht mit Dateien übereinstimmen, zu einer Nullzeichenfolge und nicht zu sich selbst erweitert werden.

Mehr Muster zu handhaben , können Sie die Kette die glob Muster: **/*.cpp **/*.h, aber vielleicht vorzugsweise, wenn die Schale Option extglob ist auf über shopt -s extglobkönnen Sie solche Konstrukte verwenden wie **/*.@(cpp|h)die mehrere Durchgänge über das Dateisystem vermeidet; einmal für jedes Muster.

Wenn Sie .fileseinbezogen werden möchten , verwenden Sie .*.cppetc oder useshopt -s dotglob

Verwenden Sie spongefrom package , um das Ändern einer Datei, die weitergeleitet wird, sicher zu handhaben moreutils(es erspart Ihnen das Erstellen Ihrer eigenen temporären Datei).


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
quelle
Viel vollständigere und informativere Antwort als die andere, +1
Nr.
+1, [[kann aber problemlos mit einer Null umgehen $f.
Enzotib
@enzotib. Vielen Dank. Ich bin nicht sicher, woher ich diese Idee habe. Es muss gewesen sein, wie die einzelne eckige Klammer funktioniert (nicht) ... zB unset x; [ -f $x ] && echo exists Berichte "existiert" ... (behoben)
Peter.O
Da die Version 4 von Bash noch nicht Mainstream ist, würde ich die **/*.@(cpp|h)mit$( find . -name "*.h" -name "*.cpp")
Matteo
3

Vielen Dank an @fred, @maxmackie, @enzotib.

Können Sie bitte das von mir befolgte Verfahren überprüfen?

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

Andernfalls wird der Lizenzheader mehrmals kopiert.

Bitte schlagen Sie mir ein Muster vor, um alle Header und Quellen im Projektverzeichnis und in den Unterverzeichnissen zu durchsuchen.

Ich konnte nicht vollständig verstehen, was @fred vorgeschlagen hat.

Satyendra
quelle
Im Allgemeinen sieht Ihr Code in Ordnung aus. Ich würde genauer darauf eingehen, wo genau sich "Copyright" befindet, z. Geben Sie die Zeilennummer und die Position in dieser Zeile an. Sie können verhindern, dass die gesamte Datei gelesen wird, indem Sie die Zeile verlassen, in der Sie "Copyright" erwarten ... zB. targln=2; findln=$(sed -rne $targln'{\|// Copyright|=;q}' "$f"); if ((findln==targln));then... aber natürlich vor allem gründlich testen ... PS. Unter Unix & Linux ist es selbstverständlich , solche Extras in Ihrer ursprünglichen Frage zu posten , nicht als Antwort ...
Peter.O
1
Einige Ratschläge: Klammern entfernen grep, -qOption hinzufügen grep. Fügen Sie immer doppelte Anführungszeichen hinzu $f.
Enzotib
1
Anführungszeichen sind von entscheidender Bedeutung, sonst werden Sie wahrscheinlich von der Wortspaltung gebissen. Als Grundregel zitieren Sie jede Erweiterung, es sei denn, Sie wissen, dass die Shell keine Wortteilung oder andere Interpretation durchführt.
Chris Down
3

Sie können dies mit exoder tun, edwenn Sie es vorziehen (Sie sollten dies nicht mit der sedvon Ihnen angeforderten sedOption tun , die zum Bearbeiten von Streams vorgesehen ist, -iwas aus verschiedenen Gründen eine schlechte Idee ist):

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
quelle
Warum ist sed -ieine schlechte Idee?
Daniel Serodio
@DanielSerodio Unterbricht standardmäßig sed -iSymlinks und Hardlinks, was zu unerwartetem Verhalten führt. Bestenfalls ist es nicht intuitiv, im schlimmsten Fall ist es aktiv schädlich.
Chris Down
2

Wenn Sie eine header_filemit gewünschten Inhalten haben:

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
quelle
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
quelle
0

Gerhard Gappmeiers Blog - Wie man rekursiv Dateiköpfe von Quelldateien ersetzt

Der Blog-Beitrag hat eine tar.gzDatei angehängt , die die benötigten Dateien enthält.

Es hat eine header.templateDatei, in die Sie einen benutzerdefinierten Kommentar schreiben können. Sie kann mehrere Zeilen umfassen.

Es verfügt über ein remove_header.awkSkript, das vorhandene Header durch den neuen Header ersetzt.

Um es auszuführen:

find . -name "*.h" -exec ~/rh/replace_header.sh {} \;
neoneye
quelle