2

I'm trying to mirror copy the whole directory from one cluster to another cluster right now. But it fails when there is a space in the name and I can't figure out how to solve this problem because it seems scp thinks I'm copying multiple files. I'm using a variable to flag the path that I need so it seems it would not be easily solved by adding a back slash.

This is the code that I'm using:

if ssh user@ip -i key test -d "'$current_dir'"; then
 echo "Directory exists. Ready to copy $dir_name."
 scp -i key -r "$current_dir/$dir_name" user@$ip:"$current_dir/$dir_name"
else
 echo Directory doesn\'t exist. Making a new directory.
 ssh user@$ip -i key mkdir "'$current_dir'"
 scp -i key -r "$current_dir/$dir_name" user@$ip:"$current_dir/$dir_name"
fi

I have tried single quote, double quotes and single quote with double quotes, but none of them works. Can anyone help me solve it? By the way, the mkdir statement in the code works.

Jonas
  • 106
  • 1
  • 6
  • 1
    What part of this is failing exactly? What is the value of `$current_dir`? What error are you getting exactly? – Etan Reisner Nov 24 '15 at 20:30
  • Hey Etan. The `$current_dir` is the variable stores the path returned from `pwd`. And the error says scp ambiguous target. – Jonas Nov 25 '15 at 15:35
  • Show the exact error and an exact value for `$current_dir` that fails. You can use `set -x` to get the shell to print the exact command it will run out when it runs it. – Etan Reisner Nov 25 '15 at 15:37
  • It shows no such file or directory after setting -x, which is reasonable because scp may treat a directory as two file when there is a space in the directory name. – Jonas Nov 25 '15 at 16:56
  • You missed the *show* part of my comment. **Show** the `set -x` and exact error output. You may very well need to escape or extra-quote the spaces in the filename so they make it through to scp but without seeing what is happening I can't be sure I even know what the problem is. – Etan Reisner Nov 25 '15 at 17:38

3 Answers3

6

As detailed in this answer, you need to use two sets of quotes, because the filename is interpreted twice: once by the local computer and once by the remote computer.

scp -i key -r "$current_dir/$dir_name" user@$ip:"'$current_dir/$dir_name'"
miken32
  • 42,008
  • 16
  • 111
  • 154
  • YES, it's successful!!! Thanks miken. I really should figure out how to use stalkoverflow well. Google didn't give me that answer. Anyway, thanks! Happy Thanksgiving. – Jonas Nov 25 '15 at 20:20
  • How does one know what shell is going to be used at the other end in order to know which quoting syntax to apply for the inner quoting? Should this method only be used in scripts where the script's author has control of the shell at the other end? – codeshot Aug 02 '19 at 17:28
  • @codeshot Very good questions, and yes, you really do need to know what shell is running at the other end (though unless it's some abomination like Windows, I think you can assume `sh` quoting). – tripleee Aug 02 '19 at 18:07
  • @codeshot I don’t know that there are any shells where wrapping an identifier in single quotes won’t insulate spaces from the shell, but – if such a thing existed – then yes: you would have to adjust for that. – miken32 Aug 02 '19 at 18:32
-1

You could escape the spaces in your directory name with sed :

current_dir = "/usr/bin/Directory With Spaces"
escaped_current_dir = `sed s/ /\\ /g $current_dir`
# escaped_current_dir = "/usr/bin/Directory\ With\ Spaces"

The string with escaped spaces will be read as one string, and one string only, which is what we want.

John Pink
  • 607
  • 5
  • 14
-1

You need to set the field separator to a space.

OIFS=$IFS  #save the original
IFS=$"\ "  #set to space
current_dir="some dir with spaces"
scp_current_dir="some\\ dir\\ with\\ spaces"
dir_name="another dir with spaces"
scp_dir_name="another\\ dir\\ with\\ spaces"
if ssh user@ip -i key test -d $current_dir; then
 echo "Directory exists. Ready to copy $dir_name."
 scp -i key -r "$current_dir/$dir_name" user@$ip:"$scp_current_dir/$scp_dir_name"
else
 echo Directory doesn\'t exist. Making a new directory.
 ssh user@$ip -i key mkdir $current_dir
 scp -i key -r "$current_dir/$dir_name" user@$ip:"$scp_current_dir/$scp_dir_name"
fi
IFS=$OIFS  #reset it back to the original
keda
  • 559
  • 2
  • 12
  • i am wondering why the down vote? was there a problem with the solution? if yes, is there a better solution? – keda Nov 24 '15 at 22:42
  • (Not my vote.) How does this help? This sets `IFS` on the local side but quoting avoids `IFS`-based splitting entirely. Presumably the remote side has the problem. – Etan Reisner Nov 25 '15 at 15:37
  • Hi Keda. I don't know who did the down vote, but I tried your solution and it didn't work. Still get the same error as scp ambiguous target. – Jonas Nov 25 '15 at 16:47
  • @Jonas is this the entire script that you are using? setting IFS should help with the spaces. if you post the whole script, i can try to see what happened. – keda Nov 25 '15 at 17:24
  • @Jonas i fixed the script slightly. now `IFS=$"\ "`. it may have been the reason it didn't work for you. try it now. – keda Nov 25 '15 at 17:32
  • `$"..."` is locale-specific quoting and not at all helpful here. And again I stress that I don't believe `IFS` on the local side is at all relevant since `"$current_dir"` was correctly quoted on the local side in all cases. Have you actually tried this solution with files with spaces in the name? – Etan Reisner Nov 25 '15 at 17:37
  • @Jonas so, the problem is with the target box. `scp` needs different escapes for spaces. i added a variable `scp_dir_name` with `\\ `. this made it work. – keda Nov 25 '15 at 17:46
  • Thank you for your suggestions, Etan. miken's solution works well for me. – Jonas Nov 25 '15 at 20:22