UNIX is cool for so many reasons, but pipes are just awesome. I
think their potential is under-utilized, probably because it's kind of
esoteric and unfamiliar to most people, even those that have been
using UNIX for a longish time (say 5 years).
I had to add a copyright notice to a bunch of files, but I'm far
too lazy to do it by hand. After all, changing a bunch of things in
the same way is what computers are good at right? So, here's a script
to do it, where it edits the file given as the first command line
argument:
#!/bin/bash
echo -n "Editing $1... "
ed -s $1 <<EOF
1i
// Some cool project
// Copyright (C) 2003-2005 Matt Hughes
.
w
q
EOF
echo "done."
ed is a program which can do scripted editing. The
commands are generally the same as vi, so 1i goes to the
first line and enters insert mode, the next three lines are the text
to insert, and the line with the '.' tells ed to exit insert mode and
return to command mode. w writes the file, and q
quits. The <<EOF syntax is shell script for "interpret everything on
the following lines until you see EOF as if it were coming from
standard input". This is also known as here document
syntax. The choice of EOF is arbitrary.
How can this be easily applied to a whole bunch of files? With
this command:
find . -name "*.java" | xargs -n 1 sh /tmp/edit.sh
The above script is saved in /tmp/edit.sh of course. The xargs
command is super-handy. Since find prints its results to
standard out, but our script needs those file names on the command
line, we can use xargs to re-arrange things.
xargs -n 1 sh /tmp/edit.sh means read from standard in,
and for each line, execute sh /tmp/edit.sh $LINE. The
-n M switch tells it to use M lines per call.
Another handy way to use xargs is to grep only
the .cc and .hh files in a source tree. Since Subversion stores a
bunch of extra files, Emacs writes ~ files, and so on, its helpful to
limit the files being searched vs. using grep directly, i.e. grep
-nr "pattern" . You could do grep -nr "pattern" .cc *.hh,
but then it wouldn't recurse because none of the directory names are
matched. Using find and xargs:
find . -name "*.cc" -or -name "*.hh" | xargs grep -n "pattern"
It's pretty handy. Of course, I hear those fancy IDE's can do this sort of stuff
too... the grepping of only relevant source files anyway.
More info about batch editing is in O'Reilly's UNIX Power tools, or
on google...