Come anteporre in modo ricorsivo un'intestazione di licenza per tutti i file .h e .cpp in una directory


19

Sto cercando di aggiungere un'intestazione di licenza a tutti i file di intestazione e file sorgente in una directory di progetto usando un ciclo for. Questo non funziona, c'è qualche altro approccio che utilizza sed?



Risposte:


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

1
Va detto che è necessario accendere globstarin bash affinché questo funzioni.
Chris Down,

E che hai bisogno di bash> 4.0 (ad esempio, Mac OS X e RedHat 5 sono ancora su 3.X)
Matteo

11

Questo è più o meno solo un commento esteso alla risposta di Daniel Serodio . Ho iniziato a scriverlo come commento, ma è diventato rapidamente troppo grande ...

Perché un globo bash sia ricorsivo, richiede shopt -s globstar. È necessario abilitare globstar, altrimenti **non funziona. L'opzione shell globstar è stata introdotta alla versione 4 di bash.

Per evitare di elaborare una directory come my.cpp/, utilizzare il test [[ -f $f ]]... Quando il test è tra parentesi quadre doppie, non è necessario che le variabili siano racchiuse tra virgolette doppie.

Puoi anche considerare la possibilità che non ci siano file corrispondenti utilizzando shopt -s nullglob, il che consente ai pattern che non corrispondono a nessun file di espandersi in una stringa nulla, anziché in se stessi.

Per gestire più pattern, è possibile concatenare i pattern glob :,**/*.cpp **/*.h ma forse preferibilmente, quando l'opzione shell extglob è attiva tramite shopt -s extglob, è possibile utilizzare tali costrutti come quelli **/*.@(cpp|h)che evitano passaggi multipli sul file system; una volta per ogni modello.

Se vuoi .filesessere incluso, usa .*.cppecc. O usashopt -s dotglob

Per gestire in sicurezza la modifica di un file che viene reindirizzato, utilizzare spongedal pacchetto moreutils(consente di risparmiare la necessità di creare il proprio file temporaneo)


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

Risposta molto più completa e istruttiva dell'altra, +1
n0pe

+1, ma [[può gestire con grazia un valore nullo $f.
enzotib,

@enzotib. Grazie. Non sono sicuro di aver avuto questa idea. Deve essere stato da come funziona la singola parentesi quadra (no) ... ad esempio i unset x; [ -f $x ] && echo exists rapporti "esiste" ... (risolto)
Peter.O

Dato che la versione 4 di bash non è ancora mainstream, sostituirò **/*.@(cpp|h)con$( find . -name "*.h" -name "*.cpp")
Matteo,

3

Grazie @fred, @maxmackie, @enzotib.

Potete per favore controllare la procedura che ho seguito.

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

in caso contrario, l'intestazione della licenza verrà copiata su più volte.

Per favore, suggeriscimi uno schema per esaminare tutte le intestazioni e le fonti nella directory del progetto e nelle sottodirectory.

Non riuscivo a capire fino in fondo cosa ha suggerito @fred.


In generale, il tuo codice sembra a posto. Sarei più specifico sull'identificazione della posizione esatta di "Copyright", ad es. specifica il numero di riga e la posizione su quella riga. Puoi impedire a sed di leggere l'intero file uscendo dalla riga in cui ti aspetti di trovare "Copyright" ... ad es. targln=2; findln=$(sed -rne $targln'{\|// Copyright|=;q}' "$f"); if ((findln==targln));then... ma, naturalmente, al di sopra e al di là di tutto il resto, prima provalo a fondo ... PS. È normale per il corso qui su Unix e Linux pubblicare tali extra nella tua domanda originale, non come una risposta ...
Peter.O

1
Alcuni consigli: rimuovere le parentesi intorno grep, aggiungere -qun'opzione a grep. Aggiungi sempre doppie virgolette $f.
enzotib,

1
Le citazioni sono fondamentali, altrimenti verrai probabilmente morso dalla suddivisione delle parole. Come regola di base, cita ogni espansione a meno che tu non sappia che la divisione delle parole o altre interpretazioni non saranno eseguite dalla shell.
Chris Down,

3

Puoi farlo con exo edse preferisci (non dovresti farlo sedcome richiesto, sedè progettato per modificare i flussi, -iè una cattiva idea per una serie di motivi):

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

Perché è sed -iuna cattiva idea?
Daniel Serodio,

@DanielSerodio Per impostazione predefinita, sed -iinterrompe collegamenti simbolici e hardlink, con conseguente comportamento imprevisto. Nella migliore delle ipotesi non è intuitivo, nel peggiore dei casi è attivamente dannoso.
Chris Down

2

Se hai un header_filecontenuto desiderato:

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

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.