Can an interactive shell become non-interactive or vice versa?
The question I'd ask would be why would anyone want to do that?
You can disable some aspects of interactive shells like:
PS1= PS2=
to disable the promptsset +m
to disable job control- disable history in some shells
- you may be able to unload the
zle
and all completion modules inzsh
.
But if you want the shell to stop being interactive, you could instead do:
. /some/file; exit
To tell it to get the rest of the commands from /some/file
(replace with /dev/tty
if you still want the commands to be read from the tty device), though there would still be some differences from non-interactive shells, like for the behaviour of return
or the fact that it would still do job control or:
exec myshell /dev/tty
To replace your current interactive shell with a non-interactive one that still reads commands from the tty device.
Note that with bash 4.4, set +i
returns with a bash: set: +i: invalid option
like in most other shells.
Related videos on Youtube
Wildcard
Updated on September 18, 2022Comments
-
Wildcard over 1 year
Can an interactive shell become non-interactive or vice versa?
Note: I've done a lot of research on the basic question, "What is the difference between interactive and non-interactive?", and the results of my research led me to ask this question.
This question has a long preamble in part because it's crucial what type of definition we use for "interactive" in order to answer it. A definition could be an arbitrary label for a certain set; it could be descriptive of various properties; or it can give you information you can use to predict behavior and understand purpose. This last type we can call an "action definition" or a "dynamic definition" and it is the most useful.
In
man 1p sh
, the following definition of an interactive shell is given:If the -i option is present, or if there are no operands and the shell’s standard input and standard error are attached to a terminal, the shell is considered to be interactive.
From the mention of "-i option" and use of the word "operands," this is referring to a shell's invocation, not attributes that could be examined in a running shell.
The Bash man page phrases it a little bit differently:
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.
The definition in the first sentence again only refers to the starting of a shell.
The second sentence (in my reading) defines conditions that are used as proxies to establish whether the shell was started in the particular ways that are defined as making it "interactive."
Note that I do not interpret this sentence as: "A bash shell is interactive if and only if
$-
includes 'i'."$-
seems to just be a handy indicator, not a definition of interactive. This is crucially relevant to my question.
Both of these (the POSIX
sh
definition and Bash's) are mechanical definitions that tell in what circumstances the label "interactive" applies to a shell you've started. They aren't action definitions as they don't give any implications of this label.However, I see that throughout the rest of the Bash man page are sprinkled references to the shell behaving in certain ways "unless it's an interactive shell" or "only in interactive shells, or if _____ option is set." (There are numerous examples and that's not the main point of this question.)
So I'll accept that "interactive" is just a convenient label for the collection of default "interactive" behaviors (option settings) described throughout the rest of the man page. It's not a fundamental term or object in itself; it has no authoritative definition outside of the shell's source code. (Unlike, for instance, the terms "open file descriptor" or "stopped process" which refer to abstractions built into the design of the kernel itself.)
(While it's also defined in the POSIX definition of
sh
, that man page [man 1p sh
] has far fewer uses of "unless the shell is interactive" and similar statements thanman bash
has, and almost exclusively focuses on invocation-time differences, so I will focus on Bash from this point onward.)
Some of the implications of a shell being "interactive" are only relevant at invocation time anyway, such as which files are sourced by the shell before it reads other commands. However, there are implications (at least in Bash) that are relevant at any time. Thus there must be a way to tell, for any given running shell, whether it is interactive or not.
Running
set +i
in an interactive Bash shell causes 'i' to be removed from the contents of$-
.The question is: Does this actually mean the shell is no longer interactive?
By Bash's exact definition, it shouldn't, since nowhere in the definition is it required that 'i' be present in
$-
: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.
A strict reading of the exact definition also raises the question: If the stdin or stderr of an interactive terminal are redirected so they are no longer connected to terminals, does the shell become non-interactive?
(It appears that the answer to this one is "no" and the man page could have included the modifier: "whose standard input and error are both connected to terminals...at the time of invocation," but I don't know definitively.)
If the answer is, "No, a shell cannot become non-interactive, nor vice versa," then what is the definitive way to determine if the shell is interactive?
Put yet another way: If there are behaviors of an "interactive shell" which persist after
set +i
, what is used to determine that those behaviors should continue to apply?
Lest anyone doubt it: There are behaviors of a shell invoked interactively which persist after
set +i
and behaviors of a shell invoked non-interactively which persist afterset -i
. For an example, consider the following excerpt fromman bash
:COMMENTS In a non-interactive shell, or an interactive shell in which the inter- active_comments option to the shopt builtin is enabled (see SHELL BUILTIN COMMANDS below), a word beginning with # causes that word and all remaining characters on that line to be ignored. An interactive shell without the interactive_comments option enabled does not allow comments. The interactive_comments option is on by default in interac- tive shells.
Thus by unsetting the
interactive_comments
option we can see a difference between interactive and non-interactive shells. The persistence of this difference is demonstrated by the following script:#!/bin/bash # When the testfile is run interactively, # all three comments will produce an error # (even the third where 'i' is not in '$-'). # When run noninteractively, NO comment will # produce an error, though the second comment # is run while 'i' IS in '$-'. cat >testfile <<'EOF' shopt interactive_comments shopt -u interactive_comments shopt interactive_comments echo $- #first test comment set -i echo $- #second test comment set +i echo $- #third test comment EOF echo 'running bash -i <testfile' bash -i <testfile echo 'running bash <testfile' bash <testfile
This confirms that "interactive" and "has
i
in the value of$-
" are not equivalent.A similar test using
${parameter:?word}
with an unset parameter produces similar results, again confirming that$-
is not the "source of truth" for shell interactiveness.
So, finally, where is the definitive 'interactiveness' trait of a shell stored?
And, can an interactive shell become non-interactive or vice versa? (...by changing this trait?)
-
Admin over 7 yearsThis question is also discussed at some length in chat.
-
Admin about 2 yearsPerhaps we can just declare that "has
i
in the value of $-" is the definition of shell interactiveness, and thus it is the source of truth. Then the first answer to "where is it stored" would be in$-
and the answer to "can a shell become interactive or vice versa" is yes, clearly. Now that simplifies your questions but then makes the definition of "interactive" more complex. But beyond the implications in the shell itself, maybe its definition is simply intent. Processes invoked by a (non)interactive shell should attempt to respect that intent though it may not be technically enforced. -
Admin about 2 yearsAlso, if you have a C program (for example) and its executed from an interactive prompt, how can that program get the value of
$-
? How are we supposed to know that intent from a non-shell program? Is that stored in a flag somewhere on the process?
-
-
Wildcard over 7 yearsThe two particular examples of behavior that I cite—
shopt -u interactive_comments
, and the "exit or not-exit" after-effect of${parameter:?word}
with unsetparameter
—do not have documented means of changing their behavior other than the question, "Is the shell interactive?" So even if it's impossible (or purposeless) to change those behaviors, the logical fact remains that there must be some place where the shell is remembering those options, independent of[ -t 0 ]
,[ -t 2 ]
or[[ $- == *i* ]]
. I want to know what that place is. -
Stéphane Chazelas over 7 years@Wildcard, if you do
exec < <(sleep infinity)
in an interactive shell, you've got an interactive shell that is not very interactive. The shell would still consider itself interactive in that$-
would still containi
, but you might not. I'm not sure there's much more to discuss about it. -
Stéphane Chazelas over 7 years@Wildcard, if the shell was started as
interactive
, it remains so. The fact that you could doset +i
in older bash versions was a bug. -
Wildcard over 7 yearsThat's good to know;
set +i
is bizarre. Makes sense it's a bug. But how is it that (using Bash 4.2) my "testfile" script could differentiate between the two times it was run at all, and produce the output that it does, when$-
didn't containi
anymore (or containedi
incorrectly)? Is there some more fundamental storage place for this attribute than$-
(that perhaps was mistakenly allowed to be out of sync with$-
before Bash 4.4)? -
Stéphane Chazelas over 7 years@Wildcard, If you look at the source code of
bash
, you'll probably find there's ainteractive
global boolean variable that maps to thei
flag of$-
. Changing that boolean will not automatically change all the behaviours of interactive shells. The changing from interactive to non-interactive is not supported. -
Wildcard over 7 yearsThat's exactly the sort of definiteness I've been trying for. Thank you! Would you mind editing that into your answer?
-
Gilles 'SO- stop being evil' over 7 years@Wildcard Dash accepts
set +i
and stops displaying a prompt. This is something that the user isn't supposed to do, so it isn't surprising that the behavior depends on the shell and is often accidental rather than the result of a deliberate decision by the shell implementer.