Your script needs to get input from another machine, perhaps to check if a file exists or a process is running.
Use SSH with public keys and command substitution. To do this, set up SSH so that you do not need a password, as described in Using SSH Without a Password. Next, tailor the command that SSH runs to output exactly what your script needs as input. Then simply use command substitution.
#!/usr/bin/env bash # cookbook filename: command_substitution REMOTE_HOST='host.example.com' # Required REMOTE_FILE='/etc/passwd' # Required SSH_USER='user@' # Optional, set to '' to not use #SSH_ID='-i ~/.ssh/foo.id' # Optional, set to '' to not use SSH_ID='' result=$( ssh $SSH_ID $SSH_USER$REMOTE_HOST "[ -r $REMOTE_FILE ] && echo 1 || echo 0" ) || { echo "SSH command failed!" >&2; exit 1; } if [ $result = 1 ]; then echo "$REMOTE_FILE present on $REMOTE_HOST" else echo "$REMOTE_FILE not present on $REMOTE_HOST" fi
We do a few interesting things here. First, notice how both $SSH_USER
and
$SSH_ID
work. They have an effect when they have a value, but when they
are empty they interpolate to the empty set and are ignored. This allows
us to abstract the values in the code, which lends itself to putting
those values in a configuration file, putting the code into a function,
or both.
# Interpolated line of the variables have values: ssh -i ~/.ssh/foo.id [email protected] [...] # No values: ssh host.example.com [...]
Next, we set up the command that SSH runs so that there is always
output (0 or 1), then check that $result
is not empty. That’s one way to make
sure that the SSH command runs (see also Telling If a Command Succeeded or Not). If $result
is empty, we
group commands using a {} code block to issue an error
message and exit. But since we’re always getting output from the SSH
command, we have to test the value; we can’t just use if[$result]; then
.
If we didn’t use the code block, we’d only issue the warning if
the SSH command returned an empty $result
, but we’d always
exit. Read the code again until you understand why, because this is an
easy way to get bitten. Likewise, if we’d tried to use a () subshell
instead of the {} code block, our intent would fail because the exit 1
would exit the subshell, not the
script. The script would then continue even after the SSH command had
failed—but the code would look almost correct, so
this might be tricky to debug.
We could have written the last test case as follows. Which form to use depends on your style and the number of statements to execute in each situation. In this case it doesn’t matter.
[ $result = 1 ] && echo "$REMOTE_FILE present on $REMOTE_HOST" || echo "$REMOTE_FILE not present on $REMOTE_HOST"
Finally, we’ve also been careful about formatting so that no lines are too long, but the code is still readable and our intent is clear.
52.14.103.77