Testing boolean condition with grep on a remote host in a bash script - bash

In a shell script I'm writing, I want to check whether a file on a remote host contains the word "open".
From the command line, I can do this successfully using
ssh user#remote_host 'grep "open" remote/folder/file'
When I was testing this in a local folder, the following worked:
if grep -q "open" local/folder/file; then
echo ...
I'm not sure how to format the conditional using ssh, though. Double quotes? Brackets? Just putting the above ssh command (which works from the command line) into brackets doesn't work:
if [ ssh user#remote_host 'grep -q "open" remote/folder/file' ]; then ...
All pointers appreciated.

Related

Bash script placing quotes around command

I have a Bash script that will get an IP to use as part of an SSH tunnel, but running this script the SSH tunnel fails. When using set -x I can see it places the arguments to the SSH command in single quotes and manually running this line results in the same error.
The Script:
ssh -N -L 9000:${ip_array[$2]}:443 ssh-server
The first argument is used elsewhere in the script for something else which is why the second is used here. ssh-server is an alias in my SSH config to the server i am tunneling through.
The output I get is:
ssh -N -L '9000:"172.0.0.1":443' ssh-server
Could this be because the script to fetch the IP returns strings to the array?
you can try removing the double-quotes first :
ip=$(echo "${ip_array[$2]}" | sed "s/\"//g")
ssh -N -L 9000:${ip}:443 ssh-server
Or just use shell parameter expansion to remove the quotes:
ssh -N -L 9000:${ip_array[$2]//"/}:443 ssh-server
That lone double quote may mess up your editor's syntax highlighting.
Get rid of the quotes by piping it through the tr command:
ssh -N -L 9000:$( echo ${ip_array[$2]} | tr -d '"' ):443 ssh-server

Write SSH command over multiple lines

I'm trying to remote login to a shell and execute a bunch of commands on the shell.
But to make it more readable, I'd like to place my code over multiple lines. How should I be doing this?
ssh -o <Option> -x -l <user> <host> " $long_command1; $long_command2; .... "
Thanks!
ssh is in fact just passing a string to the remote host. There this string is given to a shell which is supposed to interpret it (the user's login shell, which is typically something like bash). So whatever you want to execute needs to be interpretable by that remote login shell, that's the whole rule you have to stick to.
You can indeed just use newlines within the command string:
ssh alfe#sweethome "
ls /home/alfe/whatever
ping foreignhost
date
rm foobar
"
You can use the Here Documents feature of bash.
It is like:
ssh <remote-host> bash <<EOF
echo first command
echo second command
EOF
EOF marks the end of the input.
For further info: use man bash and search for Here Documents.
Edit: The only caveat is that using variables can be tricky, you have to escape the $ to protect them to be evaluated on the remote host rather then the local shell. Like \$HOSTNAME. Otherwise works with everything that is run from bash and uses stdin.
You can do like in the following example.
ssh -o <Option> -x -l <user> <host> '
pwd
whoami
ls
echo "$PATH"
'

Escape whole find content to send it to a command over ssh

I'm trying to use a ssh command like :
ssh user#host command -m MYFILE
MYFILE is the content of a file on my local directory.
I'm using Bash. I've tried to use printf "%q", but i'd not working. MYFILE contains spaces, new lines, single and doublequotes...
Is there a way my command gets the file content ? I can't actually run anything else than command on the remote host.
How about first transferring the file to the remote machine
scp MYFILE user#host:myfile &&
ssh user#host 'command -m "$(< myfile)" && rm myfile'

Why is the order of execution inversed in this bash script?

I have this script :
ssh -T user#$123.456.789.123 <<EOF
cd www
var=$(tail index.htm)
echo $var
EOF
What I thought it should do is :
Connect to the server through SSH,
then change to the folder www,
then store the tail of index.htm into the variable var
and finally echo the result.
Instead it seems that tail is executed before the change of folder, and thus doesn't find the index.htm file.
I've tried with different commands, and each time it seems the result from command substitution I'm trying to store into a variable is executed right after the SSH connexion is opened, before any other piece of script.
What am I missing here ?
The $(...) is being expanded locally, before the contents of the here document are passed to ssh. To send literal text to the remote server, quote the here document delimiter.
ssh -T user#$123.456.789.123 <<'EOF'
cd www
var=$(tail index.htm)
echo "$var"
EOF
(Also, quote the expansion of $var to protect any embedded spacing from the shell.)
The tail is running in the bash script on your local machine, not on the remote host. The substitution is getting made before you even execute the ssh command.
Your script can be replaced with simply:
ssh -T user#$123.456.789.123 tail www/index.htm
If you want to send those commands to the remote server, you can write
ssh -T user#$123.456.789.123 'cd www && var=$(tail index.htm) && echo $var'
Note that conditioning the next command on the result of the previous allows SSH to return a meaningful return code. In your heredoc, whatever happens (e.g. tail fails), SSH will return with $?=0 because echo will not fail.
Another option is to create a script there and launch it with ssh.

A script to ssh into a remote folder and check all files?

I have a public/private key pair set up so I can ssh to a remote server without having to log in. I'm trying to write a shell script that will list all the folders in a particular directory on the remote server. My question is: how do I specify the remote location? Here's what I've got:
#!/bin/bash
for file in myname#example.com:dir/*
do
if [ -d "$file" ]
then
echo $file;
fi
done
Try this:
for file in `ssh myname#example.com 'ls -d dir/*/'`
do
echo $file;
done
Or simply:
ssh myname#example.com 'ls -d dir/*/'
Explanation:
The ssh command accepts an optional command after the hostname and, if a command is provided, it executes that command on login instead of the login shell; ssh then simply passes on the stdout from the command as its own stdout. Here we are simply passing the ls command.
ls -d dir/*/ is a trick to make ls skip regular files and list out only the directories.

Resources