How to check if a shell is login/interactive/batch
I think I understand the differences between an interactive, a login and a batch shell. See the following links for more help:
- What is the difference between a ‘Login’ and an ‘Interactive’ bash shell (from the sister site: Server Fault)
- Difference between Login Shell and Non-Login Shell?
- 2.1: Types of shell: interactive and login shells (from A User’s Guide to the Z-Shell)
My question is, how can I test with a command/condition if I am on an interactive, a login or a batch shell?
I am looking for a command or condition (that returns
false) and that I could also place in an
if statement. For example:
if [[ condition ]] echo "This is a login shell" fi
csh / tcsh
tcsh I have the following in my
if($?prompt) then # Only interactive shells set $prompt ... endif
tcsh, the variable
loginsh is set for a login shell:
if($?loginsh) then # A login shell.. ... endif
tcsh also has a variable
shlvl which is set to the number of nested shells, where the login shell has a value of 1.)
Another way is to check the result of
if [ "`tty`" != "not a tty" ]; then
I’m assuming a
bash shell, or similar, since there is no shell listed in the tags.
To check if you are in an interactive shell:
[[ $- == *i* ]] && echo 'Interactive' || echo 'Not interactive'
To check if you are in a login shell:
shopt -q login_shell && echo 'Login shell' || echo 'Not login shell'
By "batch", I assume you mean "not interactive", so the check for an interactive shell should suffice.
In any Bourne-style shell, the
i option indicates whether the shell is interactive:
case $- in *i*) echo "This shell is interactive";; *) echo "This is a script";; esac
There’s no portable and fully reliable way to test for a login shell. Ksh and zsh add
$-. Bash sets the
login_shell option, which you can query with
shopt -q login_shell. Portably, test whether
$0 starts with a
-: shells normally know that they’re login shells because the caller added a
- prefix to argument zero (normally the name or path of the executable). This fails to detect shell-specific ways of invoking a login shell (e.g.
i is not the correct option to look for.
-i is to force an otherwise
non-interactive shell to become interactive. The correct auto-enabled
-s, but Bash unfortunately does not handle this correctly.
You need to check whether
s (this is granted to be
auto-activated) or whether it contains
i (this is not granted to
be auto-activated but officially only coupled to the
-i command line
option of the shell).
Here’s the answer for
fish in case any other users stumble upon this page.
if status --is-interactive # fish is interactive - that is, connected to a keyboard. # do stuff... end if status --is-login # fish is a login shell - that is, should perform login tasks such as setting up PATH # do stuff... end echo "darn, I really wanted to have to use globs or at least a case statement"
fish docs ref
UNIX/Linux has a command to check if you are on a terminal.
if tty -s then echo Terminal else echo Not on a terminal fi
You can check to see if stdin is a terminal:
if [ -t 0 ] then echo "Hit enter" read ans fi
To check whether a script runs in an interactive or non-interactive shell,
I check in my scripts for the presence of a prompt stored in the
if [ -z $PS1 ] # no prompt? ### if [ -v PS1 ] # On Bash 4.2+ ... then # non-interactive ... else # interactive ... fi
This I learned here: https://www.tldp.org/LDP/abs/html/intandnonint.html
Curiously, scripts launched off the desktop in MacOS have the same environment as those started by hand. (They have their stdin as a teletype tty, they have their
login_shell shopt unset and their
If my preferred way of bringing a script to the desktop is to create a symlink from
~/Desktop to the script, I can only guess that it was launched with a click by checking if
"$0" is an absolute path (i.e. starts with a slash).
# Checking Interactive v.s. Non-Interactive [[ -o interactive ]] && echo "Interactive" || echo "Non-Interactive" # # Checking Login v.s. Non-Login [[ -o login ]] && echo "Login" || echo "Non-Login"