Reputation: 3611
I have an init file (/etc/profile.d/which2.sh
) that aliases the which
command whenever any shell starts. In bash or sh that is fine but in zsh I don't want that as which
is a built-in that is already aware of aliases and functions. How can I have the script 'know' when it is under zsh and not execute the alias?
$0
does not help.
I have fixed the problem by simply unsetting the alias in zsh-specific ~/.zshrc, but I would like to know another way.
Upvotes: 2
Views: 630
Reputation: 437503
@rici's approach is the most robust and generic solution.
A simpler, zsh
-specific approach would be to use:
# Define a `which` alias only when NOT run by `zsh`.
[ -z $ZSH_VERSION ] && alias which ...
Some background information on how to determine the specific shell [binary] that is currently executing:
A robust option is to call the ps
utility, relying on the fact POSIX-like shells as well as csh
/ tcsh
report their own PID (process ID) via built-in variable $$
:
ps -p $$ -o "comm="
Note: ps
implementations differ with respect to what path form they report; e.g.:
macOS reports the binary path as invoked, which may be the mere file name, the full path, or even a relative path; additionally, if the shell was invoked as a login shell, such as via sudo -i
, the mere file name can be prefixed with -
(e.g., -bash
).
by contrast, the procps-ng 3.3.12
ps
implementation that comes with Ubuntu 18.04 only ever reports the file name, and never with the -
prefix.
Alternatively, for scripts that are being sourced, as initialization files are, as well as interactive shells, you can examine the value of $0
; note, however, that this is not foolproof, because the caller may have set $0
to an arbitrary value.
-
, namely if the shell is a login shell; e.g., -bash
in a shell started with sudo -i
.Note: Do NOT use $SHELL
, as it only ever reflects the current user's default shell. Its value doesn't change even when running other shells later.
Thus, a POSIX-compatible way of obtaining the current shell's executable filename is:
basename -- "${0#-}" # -> (e.g., in bash) 'bash'; will NOT work in csh/tcsh
Examples:
currShell=$(basename -- "${0#-}") # Store shell-binary filename in variable.
[ "$(basename -- "${0#-}")" = 'zsh' ] && echo "This is a ZSH shell."
If it is sufficient to test for a specific shell only, you may be able to simply test for the presence of specific environment variables such as $BASH_VERSION
, $ZSH_VERSION
, or $KSH_VERSION
.
Note, however, that not all shells have such characteristic variables; dash
, for instance, does not.
Example:
[ -n "$ZSH_VERSION" ] && echo "This is a ZSH shell."
Upvotes: 0
Reputation: 107040
What are you testing for? In the old days when we had to determine whether we were running under Kornshell or Bournshell, we could do the following test:
if [ "$RANDOM" = "$RANDOM" ]
then
echo "This is the Bourne shell"
/bin/ksh $* # Script needs the Kornshell
else
echo "This is the Kornshell"
fi
Of course, both Kornshell and Bash expand $RANDOM
(and so does zsh)...
Okay... You can find the processes running on the current tty this way:
ps -ft $(tty)
A little formatting:
$ ps -ocommand="" -t$(tty)
login -pf david
-ksh
bash
Pretty good. Shells end with sh
, so I'll make that assumption. I just want the lines ending with sh
:
$ ps -ocommand="" -t$(tty) | grep "sh$"
-ksh
bash
Yes, I'm running two shells in this TTY. I login with the Kornshell, and shelled out to bash. Let's toss the PID in the mix:
$ ps -t$(tty) -opid="" -ocommand="" | grep "sh$"
62599 -ksh
62855 bash
We want the one with the highest PID
$ ps -t$(tty) -opid="" -ocommand="" | grep "sh$" | sort -k1,1nr | head -1
62983 bash
Yup, I'm running Bash. Let's get rid of the PID:
$ ps -t$(tty) -opid="" -ocommand="" | grep "sh$" | sort -k1,1nr | head -1 | sed 's/.* //'
bash
Let's see if it works with various shells:
$ ps -t$(tty) -opid="" -ocommand="" | grep "sh$" | sort -k1,1nr | head -1 | sed 's/.* //'
ksh
Kornshell is fine.
$ ps -t$(tty) -opid="" -ocommand="" | grep "sh$" | sort -k1,1nr | head -1 | sed 's/.* //'
zsh
Works with zsh
$ ps -t$(tty) -opid="" -ocommand="" | grep "sh$" | sort -k1,1nr | head -1 | sed 's/.* //'
sh
Works with Dash or Ash
% ps -t$(tty) -opid="" -ocommand="" | grep "sh$" | sort -k1,1nr | head -1 | sed 's/.* //'
Illegal variable name.
Doesn't work in tcsh. Oh well... You can't please everybody.
Upvotes: 1
Reputation: 241701
How about
[ "$(which which)" = /usr/bin/which ] && alias which "whichever"
This doesn't verify the name of the shell; rather it verifies the shell's behaviour. That's an instance of a generally-applicable programming paradigm: test behaviour directly whenever possible. (See, for example, browser detection.)
In this case, if you just checked the shell's name as a proxy for a behaviour check, you might luck out now, but things could break in the future. The name is actually arbitrary, and new names might easily be introduced. For example, in some distros ksh
is a hard-link to zsh
; zsh
will adapt its behaviour in an attempt to emulate ksh
. As another example, I have two different zsh
versions, one of which is invoked as zsh5
.
Ideally, the test wouldn't depend on the precise location of the which
utility, either.
Upvotes: 3
Reputation: 390
The SHELL
environment variable contains the full path to the binary of your shell. You could use that (or its basename):
s=$(basename $SHELL)
[ "$s" = 'zsh' ] || alias which="what you want it to be"
Upvotes: -1