Reputation: 41990
I'm trying to set up a shell script that will start a screen
session (or rejoin an existing one) only if it is invoked from an interactive shell. The solution I have seen is to check if $-
contains the letter "i":
#!/bin/sh -e
echo "Testing interactivity..."
echo 'Current value of $- = '"$-"
if [ `echo \$- | grep -qs i` ]; then
echo interactive;
else
echo noninteractive;
fi
However, this fails, because the script is run by a new noninteractive shell, invoked as a result of the #!/bin/sh
at the top. If I source the script instead of running it, it works as desired, but that's an ugly hack. I'd rather have it work when I run it.
So how can I test for interactivity within a script?
Upvotes: 1
Views: 682
Reputation: 3937
If you want to test the value of $-
without forking an external process (e.g. grep
) then you can use the following technique:
if [ "${-%i*}" != "$-" ]
then
echo Interactive shell
else
echo Not an interactive shell
fi
This deletes any match for i*
from the value of $-
then checks to see if this made any difference.
(The ${parameter/from/to}
construct (e.g. [ "${-//[!i]/}" = "i" ]
is true iff interactive) can be used in Bash scripts but is not present in Dash, which is /bin/sh
on Debian and Ubuntu systems.)
Upvotes: 0
Reputation: 3937
Simple answer: don't run those commands inside ` ` or [ ]
.
There is no need for either of those constructs here.
Obviously I can't be sure what you expected
[ `echo \$- | grep -qs i` ]
to be testing, but I don't think it's testing what you think it's testing.
That code will do the following:
echo \$- | grep -qs i
inside a subshell (due to the ` `).[
command or built-in (depending on your shell).[
only if that string was nonempty (assuming the string didn't look like an option to [
).Some possible problems:
-qs
options to grep
should cause it to produce no output, so I'd expect [
to be testing an empty string regardless of what $-
looks like.grep
.On the other hand, if you removed the [
and backticks and instead said
if echo "$-" | grep -qs i ; then
then:
"$-"
with the value you want to test,echo ... |
would send that to grep
on its standard input,grep
would return a successful return code when that input contained the letter i
,grep
would print no output, due to the -qs
flags, andif
statement would use grep
's return code to decide which branch to take.Also:
[
command would try to replace the return code of grep
with some return code that it had tried to reconstruct by itself from the output produced by grep
.For more on how to use the if
command, see this section of the excellent BashGuide.
Upvotes: 0
Reputation: 11268
$_
may not work in every POSIX compatible sh, although it probably works in must.
$PS1
will only be set if the shell is interactive. So this should work:
if [ -z "$PS1" ]; then
echo noninteractive
else
echo interactive
fi
Upvotes: 1
Reputation: 7
You could try using something like...
if [[ -t 0 ]]
then
echo "Interactive...say something!"
read line
echo $line
else
echo "Not Interactive"
fi
The "-t" switch in the test field checks if the file descriptor given matches a terminal (you could also do this to stop the program if the output was going to be printed to a terminal, for example). Here it checks if the standard in of the program matches a terminal.
Upvotes: 0
Reputation: 1647
try tty
if tty 2>&1 |grep not ; then echo "Not a tty"; else echo "a tty"; fi
man tty : The tty utility writes the name of the terminal attached to standard input to standard output. The name that is written is the string returned by ttyname(3). If the standard input is not a terminal, the message ``not a tty'' is written.
Upvotes: 0
Reputation: 359845
Give this a try and see if it does what you're looking for:
#!/bin/sh
if [ $_ != $0 ]
then
echo interactive;
else
echo noninteractive;
fi
The underscore ($_
) expands to the absolute pathname used to invoke the script. The zero ($0
) expands to the name of the script. If they're different then the script was invoked from an interactive shell. In Bash, subsequent expansion of $_
gives the expanded argument to the previous command (it might be a good idea to save the value of $_
in another variable in order to preserve it).
From man bash
:
0 Expands to the name of the shell or shell script. This is set
at shell initialization. If bash is invoked with a file of com‐
mands, $0 is set to the name of that file. If bash is started
with the -c option, then $0 is set to the first argument after
the string to be executed, if one is present. Otherwise, it is
set to the file name used to invoke bash, as given by argument
zero.
_ At shell startup, set to the absolute pathname used to invoke
the shell or shell script being executed as passed in the envi‐
ronment or argument list. Subsequently, expands to the last
argument to the previous command, after expansion. Also set to
the full pathname used to invoke each command executed and
placed in the environment exported to that command. When check‐
ing mail, this parameter holds the name of the mail file cur‐
rently being checked.
Upvotes: 1