Bash Tips: SCP Compatibility

I’ve been using scp — part of the OpenSSH package — on a daily basis for several years now. In recent months my .bashrc files have become more complex, and at some point I started getting an annoying error message during my remote copies:

stderr is not a tty – where are you?

However charming this error message might be, I’m a little sick of seeing it. I decided to squash this one tonight, and browsing through the bash manpage and Googling did the trick.

Bash reads a wide array of configuration files on startup: ~/.bashrc is read when starting an interactive but non-login shell, ie. running bash or opening an xterm. It reads ~/.bash_profile (among others) when starting an interactive login shell, ie. logging in to a TTY in runlevel 3 or ssh’ing into a host.

To add a level of complexity to the setup, the bash run by scp runs .bashrc, though I’m not sure why. Commands in my ~/.bashrc expect stdin, stdout, and stderr to be available, but it’s obvious things aren’t working 100% as expected. After some searching, it turns out it’s fairly simple to alter .bashrc to cooperate with scp:

# only run if we have an interactive shell
if [ $(expr index "$-" i) -eq 0 ]; then
    return
fi

bash gets an environment variable “$-” that contains all its startup flags. If $- contains “i”, the shell is interactive. Our if checks for this flag; if the flag is not found, execution of .bashrc stops. I’ve put this at the top of my .bashrc for now, but at some point I will reorganize so important and non-harmful settings are still executed. (For example, $CVSROOT.)

Sharing:

 

9 Comments

  1. Michael Wilkinson says:

    Works great. Thanks for the help.

  2. Alan says:

    Wow, makes enough sense.  It fixed my problem with scp too… thanks. :)

  3. Anonymous Coward says:

    I think I’ve come up with a complete fix thanks to your hack. The message “stderr is not a tty – where are you?” is caused by biff, so by moving biff to the end of /etc/profile just after the snippet you came up with, like so:


    if [ $(expr index "$-" i) -eq 0 ]; then
      return
    fi
    if [ -x /usr/bin/biff ]; then
      biff y
    fi

    and it appears to be permanently solved. You can now source /etc/profile without any problems. The stderr message bugged me for a loooong time and it always appeared in .xsession-errors when using display managers like kdm. Thanks to you, it’s now gone. Finally it’s gone!

    Thanks.

  4. What a life saver!  I tried using:

    if [ "$TERM" = "su" ] || [ "$TERM" = "dumb" ] ; then
       exit 0;
    fi

    …which was causing “Remote server terminated connection”  HA!

  5. Actually I had problems with:
    if [ $(expr index "$-" i) -eq 0 ]; then

    I kept getting:
    expr: syntax error
    bash: [: -eq: unary operator expected

    So I changed it to:
    if [ -z "$PS1" ]; then

    Which is also unique to interactive shells.

  6. Brad Mc says:

    This pointed me in the right direction to fix a similar problem I was having with rsync.  Thanks!

  7. Jeroen says:

    Indeed, winbiff was causing this issue here too!

    Removing it from /etc/profile (on the remote computer) did the trick!

    Thanx!

  8. sang hyun says:

    Thanks.
    You saved me from annoyings.

  9. The Amigo says:

    Thanks for the post… this solved my problem too.

    My .bashrc outputs text (e.g. uname -a, uptime) and this prevented scp from working. Adding that check at the top solved the problem.

Leave a Comment

HTML: You can use these tags: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>