我有一个 init 文件 ( ),它在任何 shell 启动时/etc/profile.d/which2.sh
为该命令起别名。which
在 bash 或 sh 中这很好,但在 zsh 中我不希望它which
是一个已经知道别名和函数的内置函数。当脚本在 zsh 下并且不执行别名时,如何让脚本“知道”?
$0
没有帮助。
我已经通过简单地取消设置 zsh-specific ~/.zshrc 中的别名来解决这个问题,但我想知道另一种方法。
怎么样
[ "$(which which)" = /usr/bin/which ] && alias which "whichever"
这不会验证 shell 的名称;而是验证 shell 的行为。这是普遍适用的编程范式的一个实例:尽可能直接测试行为。(例如,请参阅浏览器检测。)
在这种情况下,如果您只是检查 shell 的名称作为行为检查的代理,您现在可能会走运,但将来可能会出现问题。该名称实际上是任意的,并且可能很容易引入新名称。例如,在某些发行版ksh
中是硬链接zsh
;zsh
将调整其行为以尝试模仿ksh
. 作为另一个例子,我有两个不同zsh
的版本,其中一个被调用为zsh5
.
理想情况下,测试也不取决于which
实用程序的精确位置。
@rici 的方法是最强大和通用的解决方案。
一种更简单、更zsh
具体的方法是使用:
# Define a `which` alias only when NOT run by `zsh`.
[ -z $ZSH_VERSION ] && alias which ...
有关如何确定当前正在执行的特定 shell [二进制] 的一些背景信息:
一个强大的选项是调用该ps
实用程序,依赖于类似 POSIX 的 shell 以及csh
/tcsh
通过内置变量报告自己的 PID(进程 ID)$$
:
ps -p $$ -o "comm="
注意:ps
实现在它们报告的路径形式方面有所不同;例如:
macOS将二进制路径报告为被调用,它可能只是文件名、完整路径,甚至是相对路径;此外,如果 shell 作为登录shell 调用,例如 via sudo -i
,则纯文件名可以以-
(例如-bash
) 为前缀。
相比之下,Ubuntu 18.04procps-ng 3.3.12
ps
附带的实现只报告文件名,从不报告前缀。-
或者,对于正在获取的脚本,如初始化文件以及交互式 shell,您可以检查 ; 的值$0
。但是请注意,这不是万无一失的,因为调用者可能已设置$0
为任意值。
-
,即如果 shell 是登录shell;例如,-bash
在以 . 开头的 shell 中sudo -i
。注意:不要使用$SHELL
,因为它只反映当前用户的默认shell。即使稍后运行其他 shell,它的值也不会改变。
因此,获取当前 shell 的可执行文件名的 POSIX 兼容方式是:
basename -- "${0#-}" # -> (e.g., in bash) 'bash'; will NOT work in csh/tcsh
例子:
currShell=$(basename -- "${0#-}") # Store shell-binary filename in variable.
[ "$(basename -- "${0#-}")" = 'zsh' ] && echo "This is a ZSH shell."
如果仅测试特定的 shell就足够了,您可以简单地测试特定环境变量的存在,例如$BASH_VERSION
、$ZSH_VERSION
或$KSH_VERSION
。
但是请注意,并非所有的 shell 都有这样的特征变量。dash
,例如,没有。
例子:
[ -n "$ZSH_VERSION" ] && echo "This is a ZSH shell."
你在测试什么?在过去,当我们必须确定是在 Kornshell 还是 Bournshell 下运行时,我们可以进行以下测试:
if [ "$RANDOM" = "$RANDOM" ]
then
echo "This is the Bourne shell"
/bin/ksh $* # Script needs the Kornshell
else
echo "This is the Kornshell"
fi
当然,Kornshell 和 Bash 都会扩展$RANDOM
(zsh 也是如此)......
好的...您可以通过这种方式找到在当前 tty 上运行的进程:
ps -ft $(tty)
一点格式化:
$ ps -ocommand="" -t$(tty)
login -pf david
-ksh
bash
非常好。贝壳以 结尾sh
,所以我会做出这个假设。我只想要以以下结尾的行sh
:
$ ps -ocommand="" -t$(tty) | grep "sh$"
-ksh
bash
是的,我在这个 TTY 中运行了两个 shell。我使用 Kornshell 登录,然后开始使用 bash。让我们把PID混合起来:
$ ps -t$(tty) -opid="" -ocommand="" | grep "sh$"
62599 -ksh
62855 bash
我们想要具有最高 PID 的那个
$ ps -t$(tty) -opid="" -ocommand="" | grep "sh$" | sort -k1,1nr | head -1
62983 bash
是的,我正在运行 Bash。让我们摆脱PID:
$ ps -t$(tty) -opid="" -ocommand="" | grep "sh$" | sort -k1,1nr | head -1 | sed 's/.* //'
bash
让我们看看它是否适用于各种 shell:
$ ps -t$(tty) -opid="" -ocommand="" | grep "sh$" | sort -k1,1nr | head -1 | sed 's/.* //'
ksh
Kornshell 很好。
$ ps -t$(tty) -opid="" -ocommand="" | grep "sh$" | sort -k1,1nr | head -1 | sed 's/.* //'
zsh
与 zsh 一起使用
$ ps -t$(tty) -opid="" -ocommand="" | grep "sh$" | sort -k1,1nr | head -1 | sed 's/.* //'
sh
适用于 Dash 或 Ash
% ps -t$(tty) -opid="" -ocommand="" | grep "sh$" | sort -k1,1nr | head -1 | sed 's/.* //'
Illegal variable name.
在 tcsh 中不起作用。哦,好吧……你不能取悦所有人。
SHELL
环境变量包含 shell 二进制文件的完整路径。您可以使用它(或其基本名称):
s=$(basename $SHELL)
[ "$s" = 'zsh' ] || alias which="what you want it to be"