Remote copy without scp
April 1st, 2009
3 comments
I often need to copy small files (configs, scripts, patches) from one machine to another and I have found using “cat” and copy-paste to be very unreliable for this: You lose tab characters, file names, permissions, and it cannot handle binaries. Plus, it gets tedious for long text files. So I added a function to my .zshrc that takes file names as an argument and prints shell code you can simply copy and paste into a remote ssh session. The current working directory will then contain the files:
rbu@localhost ~/copy-example $ ls -l
total 8.0K
-rw-r--r-- 1 rbu rbu 29 2009-04-01 17:24 doc1
-rwx--x--x 1 rbu rbu 181 2009-04-01 17:25 some-bin
rbu@localhost ~/copy-example $ copy doc1 some-bin
cat<<E=O=F | perl -MMIME::Base64 -e 'print MIME::Base64::decode(join("", <>))' - | tar xj
QlpoOTFBWSZTWbDjvy4AANl///6/SH1QLn+oZAgORH7jngCAcExyZEJgBABAYABqMEQJMAEbbbMN
QKR5TaEwAn6oxGaGiYAQDCNPTSY9QmTT0AaptKbUxGhHoaAE0aY0AAAEMJowEYTJglEinqD1Mgeo
ZGagAHqM0RkyNAD1D1PUADynlMBeffJ2xSkqIiZOGCIOv87QvSzIWsqS1GG4qIB55xMGD5cgy2Ya
IgH0wmmgmcKCEZJL0BilCat4n/ubxlVIXfIgMCABOZxo2zA0pK5IxR1+ikXrUe7bmHxeL1jyK6fe
fcO0xLbzPXYIxokkI+yKJynt03pqRDZQfBMbvdEaBRQwjQZvEhdVNDcIAOAhVyeeaKerlMFSJYBM
56ibgEosooEIAO8PC9oAbQmOVk8YoGRBgkN9wH8oaOxCgeCuu6VCljLtzvDSGdIYGcPOgRVh+LBi
u/AotDOnl/uuQtH7Md37RU6SE4jjPOLUEHLj0OIOKTNkqk1FiehcQSg62CAQ/4u5IpwoSFhx35cA
E=O=F
On the remote host you can simply paste this code:
buchholz@remotehost:~/target-dir$ ls -l
total 0
buchholz@remotehost:~/target-dir$ cat<<E=O=F | \
perl -MMIME::Base64 -e 'print MIME::Base64::decode(join("", <>))' - | tar xj
> QlpoOTFBWSZTWbDjvy4AANl///6/SH1QLn+oZAgORH7jngCAcExyZEJgBABAYABqMEQJMAEbbbMN
> QKR5TaEwAn6oxGaGiYAQDCNPTSY9QmTT0AaptKbUxGhHoaAE0aY0AAAEMJowEYTJglEinqD1Mgeo
> ZGagAHqM0RkyNAD1D1PUADynlMBeffJ2xSkqIiZOGCIOv87QvSzIWsqS1GG4qIB55xMGD5cgy2Ya
> IgH0wmmgmcKCEZJL0BilCat4n/ubxlVIXfIgMCABOZxo2zA0pK5IxR1+ikXrUe7bmHxeL1jyK6fe
> fcO0xLbzPXYIxokkI+yKJynt03pqRDZQfBMbvdEaBRQwjQZvEhdVNDcIAOAhVyeeaKerlMFSJYBM
> 56ibgEosooEIAO8PC9oAbQmOVk8YoGRBgkN9wH8oaOxCgeCuu6VCljLtzvDSGdIYGcPOgRVh+LBi
> u/AotDOnl/uuQtH7Md37RU6SE4jjPOLUEHLj0OIOKTNkqk1FiehcQSg62CAQ/4u5IpwoSFhx35cA
> E=O=F
buchholz@remotehost:~/target-dir$ ls -l
total 8
-rw-r--r-- 1 buchholz buchholz 29 Apr 1 17:24 doc1
-rwx--x--x 1 buchholz buchholz 181 Apr 1 17:25 some-bin
And now for the shell action to do this (in ZSH):
function copy() {
STR=$(tar cj $@ | perl -MMIME::Base64 -e 'print MIME::Base64::encode(join("", <>))' \
- ; exit $pipestatus[1] ) || return $?
echo "cat<<E=O=F | perl -MMIME::Base64 -e \
'print MIME::Base64::decode(join(\"\", <>))' - | tar xj"
echo "$STR"
echo "E=O=F"
}
If you are using bash, you need to replace “exit $pipestatus[1]” with “exit $PIPESTATUS” :-/