Rob Hudson wrote:
> Since I (and probably others) learn best from examples, I thought it
> would be cool if we all could share command line tricks that we've
> picked up and use often. Tricks with perl, awk, sed, xargs and all
> the other unix tools with redirects and pipes - the works.
Here are the things that come to mind early in the morning
before I've woken up. Some of these are pretty trivial...
==== Example 1 ====
Okay, I just looked in my ~/bin directory to see what I have.
I typed:
% less `grep -l /bin/sh bin/*`
==== Example 2 ====
In scripts, rather than this:
cd "$HOME/some/subdirectory"
I use this:
cd
cd some/subdirectory
I think it's slightly more readable.
The first one uses quotes in case $HOME has a space in it in some
hypothetical future. It's *much* easier to do quoting correctly
when writing scripts than to track down bugs later in scripts I've
completely forgotten about, so I'm anal about quoting in scripts.
==== Example 3 ====
I have a script called text in bin.
% cat bin/text
#!/usr/bin/perl -w- # -*-Perl-*-
foreach (@ARGV)
{
print "$_\n" if -T;
}
I use it like this.
find . -type f | xargs text | xargs grep some_pattern
That way, grep doesn't show me binary files.
==== Example 4 ====
Variations on "find ... | xargs ...":
--- Variation 1 ---
If there are files in the tree with space, tab or newline ($IFS
characters) in their names, you can use this alternate version of
find and xargs.
find ... -print0 | xargs --null ...
"-print0" tells find to separate file names with a NUL character
instead of a newline, and "--null" tells xargs to look for files
separated by a NULL character instead of a newline. NUL characters
are not legal in Unix filesystems. (They might be legal in
some foreign filesystems, e.g., Apple's HFS, but there's no
way to specify those names under Unix.)
--- Variation 2 ---
You can specify multiple directories to find. I'd use it
like this.
cd /
find `ls -1 | egrep -v 'dev|proc'` ... | xargs ...
This searches the whole disk EXCEPT /dev and /proc.
==== Example 5 ====
Copying a directory tree from here to there.
This one is well known - it's in the tar man page.
(cd dir1 && tar cf - .) | (cd dir2 && tar xfp -)
The first tar writes to standard output a tarchive of everything
in dir1. The second tar extracts the tarchive on standard input
into dir2.
I used && instead of semicolon in case I mistyped the dir names -
if either cd fails the whole command fails, rather than doing
the wrong copy.
--- Variation 1 ---
Push to a remote machine.
% (cd dir1 && tar cf - .) | ssh somehost 'cd dir2 && tar xfp -'
you@somehost's password:
--- Variation 2 ---
Pull from a remote machine.
% ssh somehost -n 'cd dir1 && tar cf -' | (cd dir2 && tar xfp -)
you@somehost's password:
This is why your .cshrc/.profile shouldn't print anything on a
non-interactive shell. A non-interactive shell is one where $prompt
(csh) or $PS1 (sh) is not set.
==== Example 6 ====
Environmentally friendly wrappers. A bunch of packages will require
that you put stuff in your environment before you use them. I get
around that by putting little scripts in my environment that set the
variables and run the programs.
A (contrived) example:
% cat bin/k2
#!/bin/sh
export KDEDIR=/opt/kde2
export QTDIR=/opt/kde2/qt
export PATH="$KDEDIR/bin${PATH:+:$PATH}"
export
LD_LIBRARY_PATH="$KDEDIR/lib:$QTDIR/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
exec "$@"
k2 runs a KDE2 command in the right environment.
==== Example 7 ====
lnhost. If I find myself logging in to host snodgrasss a lot, I can
create a new command, "snodgrass", which is short for "rsh snodgrass"
or "ssh snodgrass". I type,
% lnhost [-s] snodgrass
Now I have a new command, snodgrass. It takes the same args as
rsh/ssh, just not the hostname. E.g., I can type,
% snodgrass -n 'cd dir1 && tar cf -' | (cd dir2 && tar xfp -)
Or, I just type snodgrass.
If I need to log into snodgrass as ralph, I type this.
% lnhost [-s] ralph@snodgrass
And the command name is ralph@snodgrass.
Here's how it works.
% which lnhost
lnhost: aliased to lnhost !*:q; rehash
% which \lnhost
/home/kbob/bin/lnhost
% cat bin/lnhost
#!/bin/sh
sh=rsh
case "$1" in
-s) sh=ssh; shift;;
esac
ln -s `which $sh` $HOME/bin/hosts/$1
% echo $PATH | tr : \\12 | grep hosts
/home/kbob/bin/hosts
%
There's a lot of stuff going on here.
1. rsh and ssh look at how they're invoked. If they're invoked as
rsh/ssh then they expect the hostname to be the first argument.
Otherwise, they assume the command name is the hostname.
2. I have ~/bin/hosts in my PATH. That's a directory that has nothing
but hostname commands.
3. lnhost is a sh script that creates a symlink.
4. Because I use tcsh, I must run "rehash" after adding a new
command to my environment. bash users don't have to worry
about that.
5. You can use "echo $PATH | tr : \\12" to change a colon-delimited
list into a newline-delimited list. Very handy for $PATH,
$MANPATH, $LD_LIBRARY_PATH, $CLASSPATH. (Maybe this should
be Example 6. (-:)
That's all I can think of for now. If you guys encourage me, I'll try
to dredge up some more.
--
K<bob>
[EMAIL PROTECTED], http://www.jogger-egg.com/