5

In my reading of the bash manpage, .bashrc should only be executed when the shell is run interactively. The manpage defines interactive as:

An interactive shell is one started without non-option arguments and without the -c option whose standard input and error are both connected to terminals (as determined by isatty(3)), or one started with the -i option. PS1 is set and $- includes i if bash is interactive, allowing a shell script or a startup file to test this state.

Yet, executing a command with ssh also causes .bashrc to be run, contrary to what I would expect, given that the command is not run interactively. So, this behavior seems like a bug, but it also seems pervasive on all the versions of Red Hat and bash that I've tried. Can someone explain why this behavior is correct?

One additional point: even though .bashrc is run, $- and $PS are set as if the shell is non-interactive (as I would expect).

$ grep USER /etc/passwd
USER:x:UID:GID:UNAME:/home/USER:/bin/bash

$ cat ~/.bashrc
echo bashrc:$-,$PS1

$ bash -c 'echo $-'
hBc

$ ssh localhost 'echo $-' </dev/null 2>/dev/null
USER@localhost's password:
bashrc:hBc,
hBc

$ ssh localhost 'ps -ef | grep $$' </dev/null 2>/dev/null
USER@localhost's password:
bashrc:hBc,
USER 28296 28295 0 10:04 ? 00:00:00 bash -c ps -ef | grep $$
USER 28297 28296 0 10:04 ? 00:00:00 ps -ef
USER 28298 28296 0 10:04 ? 00:00:00 grep 28296

I am currently working around this by testing [[ $- = *i* ]] in .bashrc, but it seems as if I shouldn't have to do that.

One example server, containing no other files in my home directory than .bashrc (and .ssh) has this configuration:

$ cat /etc/redhat-release
Red Hat Enterprise Linux Server release 5.7 (Tikanga)

$ bash --version
GNU bash, version 3.2.25(1)-release (x86_64-redhat-linux-gnu)
Copyright (C) 2005 Free Software Foundation, Inc.

Versions of bash that I've tried this on: 3.00.15, 3.1.17, 3.2.25, 4.1.2 (the latter on Red Hat 6.3).

jrw32982
  • 608
  • 5
  • 11
  • From the perspective of the remote machine, the shell perhaps is interactive, even though the local machine is not making it user interactive. Can you check the command line arguments of the remote shell? – Chris Stratton May 14 '13 at 15:34
  • what is the output of your `.bash_profile` ? I'm just looking for something like `if [ -f ~/.bashrc ]; then . ~/.bashrc fi` which would activate the `.bashrc` on login. – Ewan May 14 '13 at 15:35
  • @kisamoto: `.bash_profile` is only run for a login shell. – Fred Foo May 14 '13 at 15:36
  • @Chris, see the output of ps | grep in my question. Also, why are $- and $PS1 set non-interactively but .bashrc is still run? – jrw32982 May 14 '13 at 15:36
  • @kisamoto: same behavior when there is no .bash_profile at all (see my sample configuration in my question). – jrw32982 May 14 '13 at 15:39

1 Answers1

3

From the Bash manual:

Bash attempts to determine when it is being run with its standard input connected to a network connection, as when executed by the remote shell daemon, usually rshd, or the secure shell daemon sshd. If Bash determines it is being run in this fashion, it reads and executes commands from ~/.bashrc, if that file exists and is readable. It will not do this if invoked as sh. The --norc option may be used to inhibit this behavior, and the --rcfile option may be used to force another file to be read, but rshd does not generally invoke the shell with those options or allow them to be specified.

The workaround in the default Debian bashrc skeleton is to put the following at the top of .bashrc:

# If not running interactively, don't do anything
[ -z "$PS1" ] && return
Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • I see this in the manpage now. I was confused by the description of .bashrc being used for interactive shells: "~/.bashrc: The individual per-interactive-shell startup file". – jrw32982 May 14 '13 at 15:57