Bash – Check if a file exists on a remote machine with spaces in the filename and/or path

bashscriptingstring

I have a simple bash script; I basically want to make sure that the file exists on a remote machine. I've found numerous examples of how to do this, but the missing component is how to do this with spaces in the path and/or filename being evaluated.

#!/bin/bash

HOST=server.local
DIR=/foo/bar
FILE="Foo Bar File With Spaces"


if ssh $HOST [[ -f ${DIR}/${FILE} ]]
then
   echo "The file exists"
else
   echo "The file doesn't exist."
fi

So, it fails. It gets me a syntax error in conditional expression. However, if I change the FILE variable to say:

FILE="Foo\ Bar\ File\ With\ Spaces"

The script works (it finds the file since it's there).

I have tried the following variations to my conditional expression:

if ssh $HOST [[ -f "${DIR}/${FILE}" ]]

and

if ssh $HOST [[ -f "${DIR}"/"${FILE}" ]]

Neither of which work; I know that I am missing something simple. Can someone please point me in the right direction?

Best Answer

Add an extra pair of quotes so there's one for the local shell and one for the remote shell that ssh runs.

$ dir=/tmp; file="foo bar"; 
$ ssh somewhere ls -l "'$dir/$file'"
-rw-r--r-- 1 foo foo 4194304 Oct 19 18:05 /tmp/foo bar
$ ssh somewhere [[ -f  "'$dir/$file'" ]] ; echo $?
0

You want the double-quotes on the outside so that the local shell expands the variables before the ssh command runs. With a single-quote on the inside, the remote shell won't expand special characters further.

Unless the file name contains single-quotes, that is. In which case you'll run into trouble.

To work around that, you'll need something that adds the necessary escapes to the string. Some systems have printf "%q", new versions of Bash have the ${var@Q} expansion which should do something similar similar.

$ dir=/tmp; file="\$foo' bar"
$ fullpath="$(printf "%q" "$dir/$file")"
$ ssh somewhere ls -l "$fullpath"
-rw-r--r-- 1 foo foo 0 Oct 19 18:45 /tmp/$foo' bar
Related Question