Check if a file exists on a remote machine with spaces in the filename and/or path
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 videos on Youtube
Allan
Smarter Cities and Cloud Consultant I got my start in Novell right out of high school and then cut my teeth on Sun Solaris. I am platform agnostic - meaning I use the right tool for the job. I have all flavors of operating systems macOS, Windows, and Unix. My personal stable of hardware consists of an iMac, a MacBook Pro, a Surface Pro 3, Dell Precision workstations and a Mac Pro I am attempting to refurbish - and I love them all. I much prefer FreeBSD over Linux (that's the Solaris in me) and of course OS X. My specialties are in virtualization and cloud computing. When I was working for Sun, I was doing "cloud" before it was called cloud; we called it "utility computing." I have over 25 years experience doing this, so if there's anything I can assit with, please feel free to reach out. You can reach me at the following: Email & Skype: [email protected]
Updated on September 18, 2022Comments
-
Allan over 1 year
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?
-
Allan over 7 years@Christopher It's just the way I learned to expand variables. Does it cause an issue? If I execute the command directly (not through the script) and type the path/filename out (
ssh server.local [[ -f "/foo/bar/Foo Bar With Spaces" ]] && echo "File Exists" || "File Doesn't Exist"
) it still gives me the error -
maulinglawns over 7 yearsWarning: Using a variable named
PATH
is a really bad idea! You already have aPATH
, if you change it you will face some unwanted consequences. -
Allan over 7 years@maulinglawns - True. I actually have the variables LDIR and RDIR defined in my script, but substituted PATH because it was easier to understand in the question...forgetting that there was already a PATH variable defined/declared.
-
terdon over 7 yearsAlthough not relevant here, get into the habit of never using upper case variable names. Both
PATH
andHOST
are reserved variables. Since shell reserved variables are in upper case, the simplest way to never have a conflict is to make sure your own variables are always in lower case. That said, I would also advise you to use the more portable[ -f file ]
instead of the bash (and a few other shell)-specific[[ -f file ]]
when connecting to a remote machine. Don't assume the remote shell will be the same as your local one. -
Allan over 7 years@terdon - Thanks for that. Just for the record (to save face a bit, too), my variable names were
LDIR
RDIR
andNAS
- I wrote the question with generic names. But I will start switching over to lowercase variables and will try to use more portable formats where I can.
-
-
Gilles 'SO- stop being evil' over 7 yearsNote that this fails if one of the names contains a
'
-
dave_thompson_085 over 7 years@Allan: to be exact,
ssh
passes the arguments it receives as a command to the shell on the remote system; that shell does ALL the things it normally does to a noninteractive command, usually brace tilde variable command and arithmetic expansions unless quoted (as sent), word splitting, and globbing unless disabled, as well as redirections (as sent). (But not history expansion because that's only for interactive.) -
ilkkachu over 7 years@Gilles, I think I mentioned the problem with single-quotes...
-
ilkkachu over 7 years@Allan, and it may be useful to expand some envvars like
HOSTNAME
,USER
orSSH_*
server-side. Actually you could pass them from the client to the remote side, but it requires a lenientAcceptEnv
in the sshd configuration -
ilkkachu over 7 yearsBetter yet, if the server allows
LC_*
, we can use something that's actually not used by locale, e.g.LC_filename
! Works on my Debian systems! Really, please no. This idea is so insane I'd want to give it some recognition, but on the other hand I don't really want anyone to see it.