There are heuristics that can help you, but there is no fully reliable way.
Otheus shows how to use file descriptors. That's a nice heuristic, which works in most cases. However there are edge cases where it fails, and there's no way to detect failures.
Example: take the following script.
#!/bin/sh
set
lsof -p$$ | sed 's/[0-9][0-9]*//'
Make two copies of the script, one called foo
, one called bar
. Now let's stress this a bit:
$ env -i PATH=/bin:/usr/bin perl -MPOSIX -e 'dup2(4, 11) or die $!; exec "dash", "foo", "bar"' 3<foo 4<bar </dev/null >foo.out
$ env -i PATH=/bin:/usr/bin perl -MPOSIX -e 'dup2(3, 10) or die $!; exec "dash", "bar", "foo"' 3<foo 4<bar </dev/null >bar.out
$ diff foo.out bar.out
17c17
< dash gilles 1w REG 0,24 99 10130024 /tmp/202954/foo.out
---
dash gilles 1w REG 0,24 99 10130022 /tmp/202954/bar.out
The only difference here is the file in which I logged the output.
Another case where this heuristic would fail is if the shell was invoked on standard input, or with -c
.
Another approach is to parse the shell's command line. On Linux, you can access it through /proc
. The arguments are null-delimited, which is hard to parse with portable shell tools (recent GNU tools make it easier), but it can be done. Portably, you need to call ps
to access the arguments, and there is no output format that is unambiguous: ps -o args
concatenates the arguments with spaces, and may be truncated.
Even on Linux, the problem you'll run into here is that the shell might have been invoked with options that your script isn't aware of, and one of these options might take an argument. For example, suppose you have a script called 1
and another script called 2
.
mksh -T 1 2
This invokes mksh on /dev/tty1
and runs the script 2
.
zsh -T 1 2
This invokes zsh with the cprecedences
option and runs the script 1
with the argument 2
.
You need knowledge of individual shells to tell these apart. With this method, you can detect edge cases: if you see a nonstandard option, bail out.