Two Cool Bash Tricks
I'll start off this blog with two super-cool bash shell tricks. You'll be the envy of your friends with these up your sleeve.
The "
/dev/tcp" trick
Bash does some super-cool magic when you access/dev/tcp/hostname/port. It will create a TCP socket that is connected to the named host on the given port. This lets you easily use network sockets with regular shell IO redirection. For example, the following simply prints the time from NIST:
cat < /dev/tcp/time.nist.gov/13
And YES, you can read AND write to these sockets. Here's how. The following example fetches the source for the www.google.com homepage.
exec 5<> /dev/tcp/www.google.com/80
printf "GET / HTTP/1.0\n\n" >&5
cat <&5
exec 5>&-
Check out thebash(1)manpage for more details.Process Substitution
This trick allows you to use a process *almost* anywhere you can use a file. To illustrate, let's consider thediffcommand. Most versions ofdiffrequire you to pass exactly two file names as arguments. But what if we want to diff something, like the contents of a directory, that doesn't necessarily exist in a file? This is where we can use process substitution. For example, to diff the contents of two directories, you could use:
diff <(find dir1) <(find dir2)
The syntax<(command)creates a named pipe, and attachescommand's STDOUT to the pipe. So, anything that reads from the pipe will actually be reading the output of command. To prove this to yourself, try the following:
$ echo <(/bin/true)
/dev/fd/63
$ ls -l <(/bin/true)
lr-x------ 1 jgm eng 64 Jul 13 21:50 /dev/fd/63 -> pipe:[31340331]
$ file <(/bin/true)
/dev/fd/63: broken symbolic link to pipe:[31340360]
Similarly, you can use the syntax>(command)to have thecommandread from the pipe. An example is:
tar cvf >(gzip -c > dir.tar.gz) dir
Obviously, there are better ways to accomplish taring and compressing, but the point was to use process substitution.


8 comments:
Cool, hope to see many more posts :-)
One question for you,
Could "Process Substitution" read a ssh password ?
How could we do:
diff <(ssh host1 "find /lib/modules") <(ssh host2 "find /lib/modules")
Is it possible (answering every password with keyboard)?
Thank you !
Yes, you can. I mention it briefly in the post at http://unixjunkie.blogspot.com/2006/08/old-but-useful-shell-tricks.html, but it I didn't mention the SSH part of it. Basically, that trick relies on SSH being configured to allow password-less logins using something like RSA based authentication. If you just man ssh, or google it, you'll find details on setting up RSA authentication with SSH.
Thanks greg, it is ok, i know about ssh with RSA authentication and that it will work fine inside Process Substitution.
But I'd like to know if can I get the password from keyboard (I don't like RSA authentication because I want to type password when I do something with remote hosts)
I suppose it is not possible but it will be a nice bash feature for me.
Thank you again!
Hmm, I'm not sure if you can get the sub shells started by the process substitution to read from the keyboard. But there's potentially an alternative -- the dreaded expect. You could try wrapping the ssh command in a small expect command (or script). For example, something like this would use expect to log you in via SSH and a password:
expect -c 'spawn ssh foo.bar.com cat /etc/passwd' -c 'expect password:' -c 'send P4$$w0Rd\n' -c 'expect eof'
Then you could wrap that whole mess in the process substitution. Something like:
diff <(expect -c 'spawn ssh foo.bar.com cat /etc/passwd' -c 'expect password:' -c 'send P4$$w0Rd\n' -c 'expect eof') <(cat /etc/passwd)
That mess worked on my machine. *shrug*
Thank grep
You can use sshpass http://sourceforge.net/projects/sshpass/
it is more simple that expect
True unix junkies here! You can tell from the muscle memory of the anonymous poster when he typed grep instead of greg.
@anonymous:
The solution for Your task with one remote-host is:
ssh host1 "find /lib/modules" | diff - $(find /lib/modules)
Password is prompted for host1.
host2 has to be localhost or be password-freely reachable.
ssh host1 "find /lib/modules" | diff - $(ssh host2 "find /lib/modules")
- Cocker ;wq
Post a Comment