Unix: easiest way of recursively replacing a block of multi-line text
I would like to change the license text appearing at the top of hundreds of source files. What is the easiest way of doing this?
Edit: Here is 开发者_StackOverflowan illustration of what I am trying to do:
Old File:
License 1:
xxxxxxxxxxxxx
xxxxxxxxxxxx
xxxxxxxxxxxx
xxxxxxxxxxxx
public class Foo
{
};
New File:
License 2:
yyyyyyyyyyyyyy
yyyyyyyyyyyyyy
yyyyyyyyyyyyyy
yyyyyyyyyyyyyyy
public class Foo
{
};
So, the text after the license should remain unchanged.
Thanks!
If you can identify the last line from the licence1, (so when it is not an empty line or so), you can do it for example with:
sed '1,/^the last line$/d' < $origfile | cat newlic.txt - > $newfile
You can try something like this :
newText="<your new license text>";
for file in <your files>
do
sed '1,<number of lines of your old license text>d' $file |awk -v TEXT="$newText" 'BEGIN {print TEXT}{print}' > "${file}.tmp";
mv "${file}.tmp" $file
done
You say that your "License" text is appearing in top of source files. For this, you can store your old license in a file and your new license in another file. Then run the following bash script.
dir=/home/priyank/temp/*.c #for all c files in the temp directory
for f in $dir
do
filename=$f
temp="$filename""__temp"
cat new.txt > $temp #new.txt is new license
v=`cat old.txt | wc -l`; #old.txt is old license
awk '
NR>'$v'{
print $0 >> "'$temp'";
}
' $filename
rm $filename
mv $temp $filename
done
Run this as bash script.sh
. Also, please save your original files somewhere before trying this script. It works fast. I took this as the files, and it worked perfectly. Remember not to add any extra new lines in old license file.
This is a good place to employ an ed script.
Something like:
for i in *.java; do
ed $i << \eof
1,20d
0r newlicense.txt
w
q
eof
done
It's probably a good idea to wrap this in such a way that it checks for the old license. You could make it conditional on a grep for a line in the old license, or perhaps change 1,20d
to something like /first old line/;/last old line/d
You'll need this sed command to do that replacement at the top of your files:
sed -i -n '/\(License\)/,/\(public class\)/{1h;1!H;/public class /{;g;s/\(License\).*\(public class \)/\1 2:\nyyyyyyyyyyyyyy\nyyyyyyyyyyyyyy\nyyyyyyyyyyyyyy\nyyyyyyyyyyyyyyyy\n\2/;p;};};/\(License\)/,/\(public class\)/!p' file.txt
Now to do it recursively you can combine above with find (assuming you're doing this in .txt
files):
find . -name "*.txt" -exec sed -i -n '/\(License\)/,/\(public class\)/{1h;1!H;/public class /{;g;s/\(License\).*\(public class \)/\1 2:\nyyyyyyyyyyyyyy\nyyyyyyyyyyyyyy\nyyyyyyyyyyyyyy\nyyyyyyyyyyyyyyyy\n\2/;p;};};/\(License\)/,/\(public class\)/!p' {} \;
I wrote a program to do this, which I guess I could share if necessary after some cleanup. I was clever enough beforehand to have a fixed license start pattern and license end pattern, but perhaps you can emulate this.
It deals with line prefixes, so if your bash files use # comments, and your C programs use //, and your SQL use --, it will put the proper prefix in place (using whatever was used previously).
The other trick was the use of ©. Some files were encoded in UTF-8, so I could use ©, others were encoded in a latin-1ish encoding so I used the latin-1 character, others were encoded in plain ascii so I used (c).
The final trick was the copyright date range. Copyright © 1997-2011. Different generations of management wanted different values here. From company start to this year, from file creation date to this year, individually listing each year the file was updated in, etc.
精彩评论