1

我有一个 init 文件 ( ),它在任何 shell 启动时/etc/profile.d/which2.sh为该命令起别名。which在 bash 或 sh 中这很好,但在 zsh 中我不希望它which是一个已经知道别名和函数的内置函数。当脚本在 zsh 下并且不执行别名时,如何让脚本“知道”?

$0没有帮助。

我已经通过简单地取消设置 zsh-specific ~/.zshrc 中的别名来解决这个问题,但我想知道另一种方法。

4

4 回答 4

3

怎么样

[ "$(which which)" = /usr/bin/which ] && alias which "whichever"

这不会验证 shell 的名称;而是验证 shell 的行为。这是普遍适用的编程范式的一个实例:尽可能直接测试行为。(例如,请参阅浏览器检测。)

在这种情况下,如果您只是检查 shell 的名称作为行为检查的代理,您现在可能会走运,但将来可能会出现问题。该名称实际上是任意的,并且可能很容易引入新名称。例如,在某些发行版ksh中是硬链接zshzsh将调整其行为以尝试模仿ksh. 作为另一个例子,我有两个不同zsh的版本,其中一个被调用为zsh5.

理想情况下,测试也不取决于which实用程序的精确位置。

于 2013-10-08T03:32:34.633 回答
0

@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 是登录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."
于 2014-02-19T19:53:03.860 回答
0

你在测试什么?在过去,当我们必须确定是在 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 中不起作用。哦,好吧……你不能取悦所有人。

于 2014-02-19T21:05:35.173 回答
-1

SHELL环境变量包含 shell 二进制文件的完整路径。您可以使用它(或其基本名称):

s=$(basename $SHELL)
[ "$s" = 'zsh' ] || alias which="what you want it to be"
于 2013-10-08T07:58:45.763 回答