
根据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(ksh93
和fish
)确实在那里实现了一些优化。在他们的$(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 args
。zsh
可以对其stat
, strftime
... 内置函数执行相同的操作。
有些 shell 还生成一些信息已经在一些特殊变量中自动可用,例如ksh
's$SECONDS
并$RANDOM
在其他一些 shell 中找到(以及标准变量,如$-
, $#
(例如相当于fish
's (count $argv)
))。
在 中zsh
,这已推广到 shell 的大部分内部信息,因此您几乎不需要对内置命令的输出使用命令替换。例如,它有用于内置命令、关键字、命令列表的关联数组......
if (($+builtins[echo])); then
echo echo is a builtin
fi