Non-trivial command-line fu

ssh hostA "cat file1" | tee file | ssh hostB "cat >file2"

— -sh (@rtfmsh) February 16, 2013

Alright, so this isn't very advanced at all, but perhaps it falls into the area of "non-obvious" and "useful". Also, it's one of the few instances of a useful use of cat(1), so that alone adds value.

Anyway, so you have scp(1), you have ssh tunnels and all sorts of ProxyCommand tricks up your sleeve. But still, every now and then you have two hosts that cannot talk to each other -- for example, because they are on completely segregated networks -- yet you have to transfer files between them. (Oh, and hey, let's keep a local copy on this host, too. Yay, tee(1).)

At that time, it's useful to remember that ssh(1), in good old Unix tradition, can trivially be used in a pipeline. That is, instead of trying to copy files from hostA directly to hostB, you can have your workstation or laptop function as the connecting pipeline.

The data does in fact travel from hostA to your own host, then from there to hostB, but it certainly is more convenient than running:

$ scp hostA:file /tmp/
$ scp /tmp/file hostB:

What's more, this becomes endlessly more flexible. This:

$ ssh hostA
hostA$ tar cf foo.tar foo
hostA$ exit
$ scp hostA:foo.tar .
$ ssh hostA
hostA$ rm foo.tar
hostA$ exit
$ scp foo.tar hostB:
$ ssh hostB
hostB$ tar xf foo.tar
hostB$ rm foo.tar
hostB$ exit
... becomes a single command:
$ ssh hostA "tar cf - foo" | ssh hostB "tar xf -"

Of course you can run anything on either side of the pipe -- you just need to get your quotes straight:

ssh hostA "find /dir -name '*.jpg' -print0 | xargs -0 tar cf -" |     \
        tee localcopy.tar | ssh hostB "tar xf - -C /"

The Unix pipe. Rock'n'Roll.


[previous] [Index] [next]