13

In interpreting this flowchart

enter image description here

I found that in man bash:

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.

That states that interactive login shells read /etc/profile (without --noprofile)

Also, non-interactive shells with the option --login read /etc/profile

That seems to leave some possible login shells (in which the $0 starts with a -) that being non-interactive (run an script, maybe as simple as date) may not read (source) /etc/profile.

To confirm or deny this idea:

First I tried to use su -l -, which starts a login shell with a - as the first character but I fail to make it non-interactive (and be able to present the tests to probe it).

Calling something like

$ bash -c 'date' -bash

Doesn't report to be an login shell (even if the first character is a -).

Try this to reveal the detail:

   $ bash -c 'echo "$0 $- ||$(shopt -p login_shell)||";date' -bash
      -bash hBc ||shopt -u login_shell||
      Fri Aug 19 06:32:31 EDT 2016

The $0 has a - as the first character, there is no i (interactive) in the value of $- but it is not reported as a login_shell (the -u). In this case, /etc/profile was not read, but I am not sure this is the right test.


There is also the mention of "rare non-interactive login shells" in this answer without being specific enough for this question.


The conclusion of this guy is that /etc/profile is always read.

Read the summary table: both interactive and non-interactive login shells read /etc/profile


And, if the examples from this page are correct:

Some examples

$ su bob                   # interactive non-login shell
$ su - bob                 # interactive login shell
$ exec su - bob            # interactive login shell
$ exec su - bob -c 'env'   # non-interactive login shell
$ ssh [email protected]      # interactive login shell, `~/.profile`
$ ssh [email protected] env  # non-interactive non-login shell, `~/.bashrc`

The test of exec su - bob -c 'env' reports that /etc/profile was read.


In short:

Is it possible to have a non-interactive login shell (not called with --login or -l)?

And if true, is it reading the /etc/profile file?

If the above is true we have to conclude that ALL login shells [interactive (or not)] read /etc/profile (with no --noprofile option).

Note: to detect that /etc/profile is being read, just add at the very beginning of the file this command:

echo "'/etc/profile' is being read"

4 Answers 4

4

I've seen graphical login environments that do:

exec "$SHELL" -l -c 'exec start-window-or-session-manager'

or the equivalent of:

exec -a "-$SHELL" "$SHELL" <<EOF
exec start-window-or-session-manager
EOF

So that the session initialisation file (like ~/.profile for Bourne-like shells (and the corresponding ones in /etc for some)) be read and applied.

The first one doesn't work with all shells. -l is supported by a great number of shells, but not all, and on some, like csh/tcsh, can't be used with -c. The first character of argv[0] being - is understood by all shells though, as that's what login uses to tell the shells they are login shells.

In the second case, the stdin of that shell is something other than a tty device (<< is implemented by a temporary regular file, or a pipe depending on the shell), so the shell is not interactive (the definition of interactive being when a human interacts with it).

5
  • The first one is using the --login option. For the second one, if I do exec -a "-bash" "bash" <<<"shopt -p login_shell; echo $0 $-" I get (encoded in C qoutes) $'/etc/profile read\nshopt -s login_shell\nbash himBH' so, it is login but it is interactive. We need login and non-interactive. What is it that I am missing?
    – user184899
    Aug 19, 2016 at 14:16
  • @sorontar, with <<<"$-", that $- is expanded by the calling shell because of the double quotes. The called shell is not interactive because its stdin is not a tty. Aug 19, 2016 at 14:18
  • Ah, yes, you are correct, Sir. However, correcting the mistake, we can do this:exec -a "-bash" "bash" <<\EOF shopt -p login_shell; echo $0 $- EOF to get this confirmation: $'/etc/profile read stdin: is not a tty shopt -s login_shell -bash hB' So, yes, a non-interactive login shell is possible, and it still read /etc/profile. Should we conclude that ALL login shells read /etc/profile?
    – user184899
    Aug 19, 2016 at 14:33
  • ksh makes it pretty clear that it is a non-interactive login shell, try exec -a "-ksh" "ksh" <<\EOF echo $0; set -o EOF, :).
    – user184899
    Aug 19, 2016 at 14:47
  • 1
    @sorontar, I think you can expect most shell implementations to read their session initialisation file(s) when called as login shells. Which they are depends on the shell implementation and version. In the case of bash, the start-up file handling is pretty messed-up IMO, you'll find that some systems have patched it to have a more reasonable behaviour adding even more variation. Aug 19, 2016 at 14:47
3

Yes, non-interactive login shells are possible

$ head -1 /etc/profile
echo PROFILE BEING READ

$ echo echo hello | su -
PROFILE BEING READ
stdin: is not a tty
hello

$
1
  • That is similar to this simplified: su -c 'echo hello' -. Which, to test what we need, should be written as: su -c 'echo $0 $-; shopt -p login_shell' - to get this confirming answer (encoded in C quotes): $'/etc/profile read \n -su hBc \n shopt -s login_shell'. That confirms that a login non-interactive shell was excuted and that, in the process, /etc/profile was read. Thanks.
    – user184899
    Aug 19, 2016 at 14:25
2

A non-interactive login shell is unusual, but possible. If you start the shell with the zeroth argument (which is normally the name of the executable) set to a string beginning with a -, it's a login shell, whether it's interactive or not.

$ ln -s /bin/bash ./-bash
$ echo 'shopt -p login_shell; echo $-' | HOME=/none PATH=.:$PATH -bash
shopt -s login_shell
hB

Your attempt bash -c date -bash didn't work because that doesn't tell the shell to be a login shell: the zeroth argument is bash, not -bash. After bash has started, it sets the variable $0 to -bash instead of the zeroth argument, but the zeroth argument is what matters.

You can run a noninteractive login shell with su -l or su -, but you need to arrange for standard input not to be a terminal while still being able to be authorized (without having to type a password, or arranging for your password to be at the start of the input). It may be easier with sudo: run sudo true to get a presence credential, then while the credential is still valid run echo 'shopt -p login_shell; echo $-' | sudo -i.

See also Difference between Login Shell and Non-Login Shell?

0

Is it possible to have a non-interactive login shell (not called with --login or -l)?

YES.

$ (exec -a '-' bash -c 'shopt -q login_shell && echo login shell')

However, note that /etc/profile would not be used for a non-interactve login shell unless the --login argument is given.

A common idiom that invokes a non-interactive login shell is:

$ su - someuser -c somecommand

But this suffers the fact that /etc/profile doesn't get executed.

It is possible to change this behavour but it involves customising the Bash source code at compile-time by uncommenting an option found in config-top.h:

/* Define this to make non-interactive shells begun with argv[0][0] == '-'
run the startup files when not in posix mode. */
/* #define NON_INTERACTIVE_LOGIN_SHELLS */

When I researched this su anomaly, I found that other shells including zsh and dash don't have this discrepancy.

You must log in to answer this question.