Bash: Unable to Scp or Rsync? Is Your Shell Clean?
Debugging a simple file transfer failure–a look at .bash_profile and .bashrc.
Is Your Shell Clean?
If you’ve found yourself unable to ‘scp’ or ‘rsync’ from another host, you may be misusing .bashrc.
Interestingly, ‘scp -vvv’is remarkably silent (and unhelpful) when it comes to debugging this:
# failed scp
debug2: exec request accepted on channel 0
debug1: channel 0: free: client-session, nchannels 1
debug3: channel 0: status: The following connections are open:
#0 client-session (t4 r0 i0/0 o0/0 fd 4/5 cc -1)
debug1: fd 0 clearing O_NONBLOCK
debug1: fd 1 clearing O_NONBLOCK
debug1: Killed by signal 2.
Thankfully, ‘rsync’ is far more forgiving:
# failed rsync
protocol version mismatch -- is your shell clean?
(see the rsync man page for an explanation)
rsync error: protocol incompatibility (code 2) at compat.c(176) [sender=3.1.1]
Much better! From the DIAGNOSTICS section (‘man 1 rsync’):
# man 1 rsync (Section: DIAGNOSTICS)
# Context: "protocol version mismatch -- is your shell clean?"
This message is usually caused by your startup scripts or remote shell facility
producing unwanted garbage on the stream that rsync is using for its transport.
The most common cause is incorrectly configured shell startup scripts (such as
.cshrc or .profile) that contain output statements for non-interactive logins.
Great! The most common cause has been documented.
Solution: Use .bash_profile
The cause of the file transfer failure, in this case, is that there is inappropriately placed logic in the .bashrc which is polluting the data transfer stream–logic which should likely be placed instead into .bash_profile.
To understand the nature of the failure, it is helpful to understand how bash fundamentally handles interactive login and non-login shells.
From the INVOCATION section of the bash man pages:
# man 1 bash (Section: INVOCATION)
When bash is invoked as an interactive login shell, or as a non-interactive
shell with the --login option, it first reads and executes commands from the
file /etc/profile, if that file exists. After reading that file, it looks for
~/.bash_profile, ~/.bash_login, and ~/.profile, in that order, and reads and
executes commands from the first one that exists and is readable.
When an interactive shell that is not a login shell is started, bash reads and
executes commands from /etc/bash.bashrc and ~/.bashrc, if these files exist.
In short, if you have custom bash logic which generates unique output(s), and you’re planning on starting an interactive, non-login shell (via a tool like ‘scp’, ‘rsync’, etc.), use .bash_profile, not .bashrc.