62

I've been experiencing very strange behavior of SCP for some time: whenever I try to copy a file, the output of SCP contains a bunch of underscores and the file is not copied.

$ scp test.txt 192.168.0.2:~
job@192.168.0.2's password: 
 ________________________________________

When I create an SSH connection using Midnight Commander and copy files it does work.

Some info about my machine:

$ ssh -V
OpenSSH_5.8p1 Debian-1ubuntu3, OpenSSL 0.9.8o 01 Jun 2010

$ uname -a
Linux squatpc 2.6.38-10-generic #46-Ubuntu SMP Tue Jun 28 15:05:41 UTC 2011 i686 i686 i386 GNU/Linux

And I'm running Kubuntu 11.04.

Edit: Some more info as requested by the comments:

$ scp -v test.txt 192.168.0.2:~
Executing: program /usr/bin/ssh host 192.168.0.2, user (unspecified), command scp -v -t -- ~
OpenSSH_5.8p1 Debian-1ubuntu3, OpenSSL 0.9.8o 01 Jun 2010
debug1: Reading configuration data /etc/ssh/ssh_config
debug1: Applying options for *
debug1: Connecting to 192.168.0.2 [192.168.0.2] port 22.
debug1: Connection established.
debug1: identity file /home/job/.ssh/id_rsa type 1
debug1: Checking blacklist file /usr/share/ssh/blacklist.RSA-2048
debug1: Checking blacklist file /etc/ssh/blacklist.RSA-2048
debug1: identity file /home/job/.ssh/id_rsa-cert type -1
debug1: identity file /home/job/.ssh/id_dsa type -1
debug1: identity file /home/job/.ssh/id_dsa-cert type -1
debug1: identity file /home/job/.ssh/id_ecdsa type -1
debug1: identity file /home/job/.ssh/id_ecdsa-cert type -1
debug1: Remote protocol version 2.0, remote software version OpenSSH_5.8p1 Debian-1ubuntu3
debug1: match: OpenSSH_5.8p1 Debian-1ubuntu3 pat OpenSSH*
debug1: Enabling compatibility mode for protocol 2.0
debug1: Local version string SSH-2.0-OpenSSH_5.8p1 Debian-1ubuntu3
debug1: SSH2_MSG_KEXINIT sent
debug1: SSH2_MSG_KEXINIT received
debug1: kex: server->client aes128-ctr hmac-md5 none
debug1: kex: client->server aes128-ctr hmac-md5 none
debug1: sending SSH2_MSG_KEX_ECDH_INIT
debug1: expecting SSH2_MSG_KEX_ECDH_REPLY
debug1: Server host key: ECDSA 28:f3:2b:31:36:43:9b:07:d8:33:ca:43:4f:ca:6c:4c
debug1: Host '192.168.0.2' is known and matches the ECDSA host key.
debug1: Found key in /home/job/.ssh/known_hosts:20
debug1: ssh_ecdsa_verify: signature correct
debug1: SSH2_MSG_NEWKEYS sent
debug1: expecting SSH2_MSG_NEWKEYS
debug1: SSH2_MSG_NEWKEYS received
debug1: Roaming not allowed by server
debug1: SSH2_MSG_SERVICE_REQUEST sent
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug1: Authentications that can continue: publickey,password
debug1: Next authentication method: publickey
debug1: Offering RSA public key: /home/job/.ssh/id_rsa
debug1: Authentications that can continue: publickey,password
debug1: Trying private key: /home/job/.ssh/id_dsa
debug1: Trying private key: /home/job/.ssh/id_ecdsa
debug1: Next authentication method: password
job@192.168.0.2's password: 
debug1: Authentication succeeded (password).
Authenticated to 192.168.0.2 ([192.168.0.2]:22).
debug1: channel 0: new [client-session]
debug1: Requesting no-more-sessions@openssh.com
debug1: Entering interactive session.
debug1: Sending environment.
debug1: Sending env LANG = en_US.UTF-8
debug1: Sending command: scp -v -t -- ~
 ________________________________________
debug1: client_input_channel_req: channel 0 rtype exit-status reply 0
debug1: channel 0: free: client-session, nchannels 1
debug1: fd 0 clearing O_NONBLOCK
debug1: fd 1 clearing O_NONBLOCK
Transferred: sent 2120, received 1872 bytes, in 0.3 seconds
Bytes per second: sent 7783.1, received 6872.6
debug1: Exit status 0

and

$ type scp
scp is hashed (/usr/bin/scp)
mtvec
  • 2,738

5 Answers5

110

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.

mtvec
  • 2,738
  • 1
    echo "don't have a cow" | cowsay – Stéphane Gimenez Aug 12 '11 at 17:22
  • Wow, after months of scp just being broken, you finally illuminated the answer for me. I would have never thought of this. I just did a mv ~/.bashrc ~/.bashrc.bak to test and make sure that was the problem, and it worked after I did that. – Jondlm Dec 02 '15 at 22:32
  • @ScottStensland This needs to go at the top of the remote .bashrc. The local one is irrelevant. Note that there was a typo in my comment (the answer is correct): it's *i*, not *-*. – Gilles 'SO- stop being evil' Apr 10 '18 at 17:48
  • NO NO NO. rtfm. bashrc is run for non-interactive shells. If you want happy cow messages when you login change your bash_profile. If you want cow wisdom every time you open a X-Window then try to work out if this is one of MANY scenarios in which you should not be writing the terminal - https://unix.stackexchange.com/questions/9605/how-can-i-detect-if-the-shell-is-controlled-from-ssh – symcbean Apr 10 '18 at 20:48
  • Saved my bacon. Thanks. – Mr.Glaurung Jun 27 '22 at 10:40
7

AFAIK, the right way to enable un-hindered scp is less about which conditional for stdout in your ~/.bashrc script, and more about simply restricting screen output to the ~/.bash_profile script. At least that is how it works for my distro (CentOS.)

Edit for clarity:

  1. Put only lines in your ~/.bashrc file as required by "all" remote conections (i.e. setting certain ENV vars is OK, but echoing human-readable text is not.)
  2. YMMV
  • mind expounding? i.e. how to restrict screen output to the .bash-profile ? – WestCoastProjects Jul 07 '14 at 03:31
  • 1
    By screen output, I mean echo "Greetings, Master" or anything else that displays output to the terminal window. Don't put that in your ~/.bashrc --keep it in your ~/.bash_profile script. – Mark Hudson Sep 09 '14 at 04:31
1

This behavior might occur when your .bashrc file produce some output or you have MOTD(Message Of The Day).You can use the -o option with scp:

With -o you can pass options to SSH, in this case you can give option like RequestTTY=no and it never requests terminal output.

scp -o RequestTTY=no source target
Thor1n
  • 11
  • As it’s currently written, your answer is unclear. Please [edit] to add additional details that will help others understand how this addresses the question asked. You can find more information on how to write good answers in the help center. – Community Feb 25 '23 at 13:58
  • Alright. I'll make a little bit understandable. – Thor1n Feb 26 '23 at 17:57
0

@Job is right. However, this problem might become a bigger issue when the welcome screen graphic is part of /etc/bash.bashrc

You will have to make sure you clear such welcome graphic content from both:

  1. /etc/bash.bashrc
  2. ~/.bashrc

On debian & ubuntu systems, on a non-interactive shell, /etc/bash.bashrc is first called before ~/.bashrc

0

I am not sure with this error at scp, it is long time ago, when I used it. I replaced scp with rsync and it is much better. Rsync should be at almost evere Linux device.

I wrote about rsync here, in tread about scp: How can I best copy large numbers of small files over scp?

Rsync is described there by post from JohnU.

JohnU
  • 11