Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm trying to add a license header to all header files and source files in a project directory using a for loop. This is not working, is there any other approach using sed?

share|improve this question
1  
Very similar case: unix.stackexchange.com/questions/20577/… –  pbm Sep 13 '11 at 17:33
    
Related (has some Python code examples): language agnostic - Tool for adding license headers to source files? - Stack Overflow –  sdaau Jul 4 at 15:11

4 Answers 4

for f in **/*.cpp; do
  cat header_file $f > $f.new
  mv $f.new $f
done
share|improve this answer
1  
It should be mentioned that you need to turn on globstar in bash for this to work. –  Chris Down Sep 15 '11 at 9:44
    
And that you need bash > 4.0 (e.g., Mac OS X and RedHat 5 are still on 3.X) –  Matteo Sep 16 '11 at 17:32

This is more or less just an extended commentary on Daniel Serodio'` answer. I started writitng it as a comment, but it quickly grew too large...

For a bash glob to be recursive, it requires shopt -s globstar. You must enable globstar, otherwise ** doesn't work. The globstar shell option was introduced to version 4 of bash.

To avoid processing a directory such as my.cpp/, use the test [[ -f $f ]]... When the test is in double square-brackets, variables don't need to be double quoted.

You can also consider the possibility of there being no matching files by using shopt -s nullglob, which allows patterns which match no files to expand to a null string, rather than themselves.

To handle multiple patterns, you can chain the glob patterns: **/*.cpp **/*.h, but perhaps preferrably, when the shell option extglob is on via shopt -s extglob, you can use such constructs such as **/*.@(cpp|h) which avoids multiple passes over the file system; once for each pattern.

If you want .files to be included, use .*.cpp etc, or use shopt -s dotglob

To safely handle modifying a file which is being piped, use sponge from package moreutils (it saves you the need to create your own temp file)


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
share|improve this answer
    
Much more complete and informative answer than the other one, +1 –  MaxMackie Sep 14 '11 at 2:05
    
+1, but [[ can gracefully handle a null $f. –  enzotib Sep 14 '11 at 7:23
    
@enzotib. thanks. I'm not sure were I got that idea from. It must have been from how the single square-bracket works (doesn't)... eg unset x; [ -f $x ] && echo exists reports "exists" ... (fixed) –  Peter.O Sep 14 '11 at 9:12
    
Since version 4 of bash is not mainstream yet I would substitute the **/*.@(cpp|h) with $( find . -name "*.h" -name "*.cpp") –  Matteo Sep 16 '11 at 17:35

Thank you @fred, @maxmackie, @enzotib.

Can you please check the procedure I have followed.

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

otherwise the license header will be copied to multiple number of times.

Please suggest me a pattern to go through all the headers and sources in project directory and subdirectories.

I could not understand fully what @fred has suggested.

share|improve this answer
    
In general, your code looks okay. I would be more specific about identifying the exact location of "Copyright", eg. specify the line number and position on that line. You can prevent sed reading the entire file by quitting on the line where you expect to find "Copyright"... eg. targln=2; findln=$(sed -rne $targln'{\|// Copyright|=;q}' "$f"); if ((findln==targln));then ... but, of course, above and beyond everything else, thoroughly test it first... PS. It is par for the course here at Unix & Linux to post such extras in your original question, not as an answer... –  Peter.O Sep 15 '11 at 7:56
1  
Some advices: remove parentheses around grep, add -q option to grep. Always add double quotes around $f. –  enzotib Sep 15 '11 at 8:04
1  
Quotes are vital, otherwise you will be likely bitten by word splitting. As a basic rule, quote every expansion unless you know that word splitting or other interpretation will not be performed by the shell. –  Chris Down Sep 15 '11 at 12:07

You can do this with ex or ed if you prefer (you should not do this with sed as you requested, sed is designed to edit streams, -i is a bad idea for a variety of reasons):

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
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.