A shell-centric view of the world
If you spend a lot of time at the computer and learn to watch yourself as you
work, you often find yourself repeating sequences of operations and looking
for ways to automate them. As a result one's interface to the computer grows
organically over the years around one's mental habits and personal
idiosyncracies. Some scalings from my shell (
zsh or
bash):
Just because I am a CLI
bigot doesn't mean I am entirely closed to the possibilities of a GUI
environment. Ever have a bunch of data in a file that you wished you could
just 'see'? Wouldn't it be nice, for example, to be able to say:
$ grep "^Date: " mail |column 3 |freq |plot with lines
and have it pop up a graph in a new window? Here's an implementation for
plot:
plot () {
( echo "plot \"-\"" "$@" ; cat ) |gnuplot -persist
}
A nice bonus: plot passes its arguments straight to gnuplot's
plot command. Want bargraphs?
plot with impulses
Ugly, but functional.
Taking the idea further, consider Pipe Viewer - a clone for
cat that shows a text progress bar as it works. Really nice, except
it can munge an app's stderr stream. Wouldn't it be much nicer to have it pop
up a progress bar instead? Armed with progress we
can now say things like:
gpv () {
{ pv -f "$@" 3>&2 2>&1 1>&3 |progress "$@" ; } 2>&1
}
So this pipe will pop up a progress bar as gnuplot crunches through a large
data file:
$ gpv data_file |column 4 |normalize |cumulative |plot with lines
Being able to create and manipulate GUI widgets in shell scripts opens up a
whole new modality for them.
The plot command above can be thought to be
obtained by taking a command under a subordinate shell - gnuplot - and 'exporting' it to the
top-level shell. This happens to me all the time: I get used to typing a
command in a subordinate shell, start typing it in my shell by mistake, and
eventually go, "Aha!" A case in point: when I started using p[rint]
in gdb as my
calculator, it was
only a matter of time before I wanted to have the same command in my shell.
p () {
echo "$@" |bc -l
}
Google for my email? I'd rather actively delete junk
so I can grep without having to index:
mgrep () {
agrep -id '^From ' "$1" $MAILDIR/* > $MAILDIR/x
pine -i -f x
rm $MAILDIR/x
}
Photo albums with thumbnails in a dozen lines:
album () {
ls *.{jpg,JPG} > index.html 2>/dev/null
# Thumbnails.
for i in `cat index.html`
do
djpeg $i |pnmscale -height 300 \
|cjpeg > `echo "$i" |perl -pwe 's/jpg$|JPG$/t.jpg'`
done
cat > x << EOF
%s/.*/& &/
%s/\.jpg$/.t.jpg/i
%s/jpg /jpg"><img src="/i
%s/^/<p><a href="/
%s/$/"><\/a>/
EOF
vim -c "so x |wq" index.html
}
If you think you need to split the generated html into multiple files you
probably have too many pictures for your audience's liking.
One of my oldest and most-used scripts lets me easily
specify arbitrary paths to cd into:
$ pwd
/some/long/dir/ect/ory/str/uct/ure
$ cd arch
/another/inode/deep/down/the/fs/hier/archy
$ cd herfs arch
/yet/anoth/er/inode/deep/down/the/otherfs/hie/rarchy
Much more general than CDPATH. It works by picking the first acceptable
directory in ~/.dirlist:
cd () {
command cd "$@" 2>/dev/null && return
ARG=`echo "$@" |perl -pwe 's# +#.*\/.*#g'`
DIR=`grep $ARG ~/.dirlist`
[ "$DIR" ] && command cd $DIR
}
There are a variety of ways to maintain ~/.dirlist, ranging from cron jobs
that periodically run:
find ~ -type d > ~/.dirlist
to overloading mkdir, rmdir, rm, cp, mv.. Crucial decisions are what portions
of the file system to index, and how to order paths with common names like in
the above example.
Easy access to shell color escape codes. Example usage:
echo `color red`foo`color reset`
...
footnotes
0.
This graph plots by date the #mails I sent/received for the month of November
2004. Notice the spike right before the presidential elections.
1.
The other commands in that pipe are simple stubs in
perl. I have a lot of those.
2.
Requires
python and
wish.
3.
A habit I picked up from
Karu.
4.
agrep is a better
grep.
5.
Requires
netpbm and
vim.