在没有子 shell 的情况下比较 if 语句内的命令输出

在没有子 shell 的情况下比较 if 语句内的命令输出

根据https://www.gnu.org/software/bash/manual/bashref.html#Command-Grouping

将命令列表放在大括号之间会导致该列表在当前 shell 上下文中执行。

但是当我尝试这个时:if [[ { type -t echo; } = "builtin" ]]; then echo 1; else echo 0; fi我收到以下错误:

-bash:需要条件二元运算符

-bash:“type”附近的语法错误

没关系,我知道它不应该这样使用。现在我知道,如果我使用的话,if [[ $( type -t echo ) = "builtin" ]]; then echo 1; else echo 0; fi理论上我会实现所需的功能。

我发现其他关于防止不必要地使用子 shell 的问题都得到了回答,但没有一个问题解释了如何比较没有子 shell 的命令的输出。我真正想要的是避免在不需要的地方使用子 shell,如果可能的话,我真的希望在当前 shell 上下文中运行此检查 - 感觉这才是应该做的。PS 如果没有其他办法,我不介意使用变量和操作。

答案1

要获取命令的输出,您需要以某种方式读取它。type将其写入其标准输出。我们需要以某种方式获取它并将其传递给[命令。

$(...)为此使用管道。但对于管道,您需要一个编写器和一个读取器进程,因此即使要运行内置命令,您也必须分叉一个进程。您可以尝试在同一进程中读取和写入管道,但这通常很容易出现死锁,因为如果没有人读取,写入可能会被阻塞(尽管您需要管道缓冲区填满才能发生这种情况,但这种情况不太可能发生type)。

yash您可以使用具有原始接口的 shell 来完成此操作pipe()

{
  type echo >&3
  echo 3>&- # close the writing end so the reader can see an eof
  IFS= read -r answer <&4
} 3>>|4

type上面,如果的输出大于管道缓冲区大小(在现代版本的 Linux 上默认为 64KiB),则会出现死锁。

使用bash,您始终可以执行以下操作:

type -t echo > file
IFS= read -rd '' type < file
if [ "$type" = builtin ]...

但是,虽然这避免了子 shell,但这意味着文件系统会被该file.

type是一个内置的。它的输出是由 shell 生成的,确实,必须分叉一个进程才能在 shell 中使用该输出感觉有点愚蠢。

一些 shell(ksh93fish)确实在那里实现了一些优化。在他们的$(type echo)( (type echo)in fish) 中,他们实际上伪造了输出的写入和读取(FreeBSDsh也对单个内置调用执行此操作(如此type处))。当内置函数的 stdout 是命令替换时,shell 不会写入输出,而是将可能输出的文本附加到命令替换结果中,并且不需要 fork。

实际上,fish's(type echo)更像ksh93's ,${ type echo;}因为它甚至不创建子 shell 环境。和$(...)ksh93 模仿一个子 shell 环境,这样看起来就好像一个子进程被分叉来解释其中的代码,并且不会对其${ ...;}变体执行此操作。

ksh93$ a=1
ksh93$ echo "$(a=2; type echo) $a"
echo is a shell builtin 1
ksh93$ echo "${ a=3; type echo;} $a"
echo is a shell builtin 3

fish> set a 1
fish> echo (set a 2; type echo) $a
echo is a builtin 2

您会发现,在某些不进行优化的 shell 中,可以通过以下方式调用许多内置函数,即不写入结果,而是将其存储在变量中。

最明显的是标准read,并且getopts默认情况下会这样做(您会这样做IFS= read -r var而不是var=$(line))。bash并且zsh还有printf -v variable format argszsh可以对其stat, strftime... 内置函数执行相同的操作。

有些 shell 还生成一些信息已经在一些特殊变量中自动可用,例如ksh's$SECONDS$RANDOM在其他一些 shell 中找到(以及标准变量,如$-, $#(例如相当于fish's (count $argv)))。

在 中zsh,这已推广到 shell 的大部分内部信息,因此您几乎不需要对内置命令的输出使用命令替换。例如,它有用于内置命令、关键字、命令列表的关联数组......

if (($+builtins[echo])); then
  echo echo is a builtin
fi

相关内容