Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Pipe script and binary data to stdin via ssh

Tags:

bash

ssh

tar

I want to execute a bash script remotely which consumes a tarball and performs some logic to it. The trick is that I want to use only one ssh command to do it (rather than scp for the tarball followed by ssh for the script).

The bash script looks like this:

cd /tmp
tar -zx
./archive/some_script.sh
rm -r archive

I realize that I can simply reformat this script into a one-liner and use

tar -cz ./archive | ssh $HOST bash -c '<commands>'

but my actual script is complicated enough that I must pipe it to bash via stdin. The challenge here is that ssh provides only one input pipe (stdin) which I want to use for both the bash script and the tarball.

like image 531
mxxk Avatar asked May 08 '14 22:05

mxxk


1 Answers

I came up with two solutions, both of which include the bash script and the tarball in stdin.

1. Embed base64-encoded tarball in a heredoc

In this case the server receives a bash script with the tarball is embedded inside a heredoc:

base64 -d <<'EOF_TAR' | tar -zx
<base64_tarball>
EOF_TAR

Here's the complete example:

ssh $HOST bash -s < <(
# Feed script header
cat <<'EOF'
cd /tmp
base64 -d <<'EOF_TAR' | tar -zx
EOF

# Create local tarball, and pipe base64-encoded version
tar -cz ./archive | base64

# Feed rest of script
cat <<'EOF'
EOF_TAR
./archive/some_script.sh
rm -r archive
EOF
)

In this approach however, tar does not start extracting the tarball until it is fully transferred over the network.

2. Feed tar binary data after the script

In this case the bash script is piped into stdin followed by the raw tarball data. bash passes control to tar which processes the tar portion of stdin:

ssh $HOST bash -s < <(
# Feed script.
cat <<'EOF'
function main() {
  cd /tmp
  tar -zx
  ./archive/some_script.sh
  rm -r archive
}
main
EOF
# Create local tarball and pipe it
tar -cz ./archive
)

Unlike the first approach, this one allows tar to start extracting the tarball as it is being transferred over the network.

Side note

Why do we need the main function, you ask? Why feed the entire bash script first, followed by binary tar data? Well, if the binary data were put in the middle of the bash script, there would be an error since tar consumes past the end of the tarfile, which in this case would eat up some of the bash script. So, the main function is used to force the whole bash script to come before the tar data.

like image 67
mxxk Avatar answered Oct 07 '22 11:10

mxxk