Ok LOL, I just figured out what the problem is.
Since I like cows so much, I've put fortune | cowsay
at the top of my .bashrc
file which produces output like the following when starting bash
:
_______________________________________
< You will lose an important disk file. >
---------------------------------------
\ ^__^
\ (oo)\_______
(__)\ )\/\
||----w |
|| ||
This is all fine (and sometimes funny) when running bash
interactively. However, bash reads ~/.bashrc
when it is interactive and not a login shell, or when it is a login shell and its parent process is rshd
or sshd
. When you run scp
, the server starts a shell which starts a remote scp
instance. The output from .bashrc
confuses scp
because it is sent the same way the scp
protocol data is sent. This is apparently a known bug, see here for more details.
Also note that the underscores I mentioned in the question are those in the top line of the text balloon.
So the solution was simple: I put the following at the top of .bashrc
on the remote (destination) machine:
# If not running interactively, don't do anything
[[ $- == *i* ]] || return
This line is present in the default .bashrc
but was put way down because of my many (apparently careless) edits.
The reason for this is that one of the login scripts on the target server is using stty...
to set up terminal characteristics. The command fails when it doesn't have a tty, ie when you connect with scp
.
The solution is to protect the stty
so that it runs only when an interactive session is present. There are a number of ways to do this; here are some examples for bash/sh type shells:
Ugly:
stty ... >/dev/null 2>&1
Works for me:
test -n "$PS1" && stty ...
Recommended elsewhere on SE:
# Check for a bash login shell
case $- in
*i*) stty ... ;;
esac
Best Answer
This is interesting. The other answers that I'm seeing are telling you to swap your escaped quote and escaped space for a quoted string. Actually they're equivalent so you'll see no change (
a\'\ b
is the same to the shell as"a' b"
).The problem here lies in the way that
scp
on the remote system interprets the command line that it's being given.As an example, this would work:
But this would fail:
(I've used
localhost
for the example; you should useuser@host
for your situation.)If you include the
-v
(verbose) flag onscp
you can see exactly what's going on that gives rise to the failure:The unfortunate solution here is that you need to escape special characters (including whitespace) twice - once for the local shell, and once for the remote shell: