A. *_*dry 5 history shell-builtin command
我知道该命令command
是在最新的 POSIX 标准中指定的,而builtin
不是。我也意识到这两个命令都是常规的内置命令(即它们可以被用户定义的函数覆盖)。一些外壳定义了builtin
,但不是全部(例如dash
没有)。我想了解为什么builtin
在某些 shell 中引入。
据我所知,builtin
只会返回特殊的然后是常规的内置函数,但是command
会返回特殊的内置函数,然后是常规的内置-p
函数,然后是路径上的命令(并且可以使用开关command
来指定它使用外壳定义的默认值$PATH
,以防用户修改$PATH
)。
例如,在 中mksh
,我看到以下内容:
(注意: mksh
从 repo 安装在 Ubuntu 20.04 上http://archive.ubuntu.com/ubuntu focal/universe amd64 mksh amd64 58-1
)
$ echo $KSH_VERSION
@(#)MIRBSD KSH R58 2020/03/27
$ which -a echo
/usr/bin/echo
/bin/echo
$ which -a printf
/usr/bin/printf
/bin/printf
$ type echo
echo is a shell builtin
$ type printf
printf is /usr/bin/printf
$ command echo 'Hello World!'
Hello World!
$ command printf 'Hello World!\n'
Hello World!
$ builtin echo 'Hello World!'
Hello World!
$ builtin printf 'Hello World!\n'
mksh: builtin: printf: not found
$ sudo cp /usr/bin/printf /usr/bin/printf.backup
$ sudo cp /bin/printf /bin/printf.backup
$ sudo rm /usr/bin/printf
$ sudo rm /bin/printf
rm: cannot remove '/bin/printf': No such file or directory
$ sudo cp /usr/bin/printf.backup ~/printf
$ echo $PATH | sed 's/:/\n/g'
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
# ...remainder ommitted here for brevity
$ export PATH=~:$PATH
$ echo $PATH | sed 's/:/\n/g'
/home/my_username
/usr/local/sbin
/usr/local/bin
/usr/sbin
/usr/bin
/sbin
/bin
/usr/games
/usr/local/games
# ...remainder ommitted here for brevity
$ command printf 'Hello World!\n'
Hello World!
$ command -p printf 'Hello World!\n'
mksh: printf: inaccessible or not found
Run Code Online (Sandbox Code Playgroud)
我的理解正确吗?或者,做command
和builtin
做完全相同的事情(如果是这样,为什么要builtin
引入?)?或者,command
和之间是否还有另一个细微的区别builtin
?
(我试过在 StackExchange 上寻找答案,但没有找到任何东西,所以如果有人能指出我合适的答案,我将非常感激。)
更新:
还值得注意的是command
,builtin
“跳过”搜索和使用定义的别名。在 POSIX shell 评估顺序中,别名扩展出现在命令搜索和评估之前,算术、变量和文件通配符扩展也是如此。但是,算术、变量和通配符在command
and内计算builtin
,而不是别名。似乎文件应该提到的东西。
例如:
$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ command echo $((1 + 1))
2
$ builtin echo $((3 + 1))
4
Run Code Online (Sandbox Code Playgroud)
但
$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ alias \[='echo hello'
$ [
hello
$ if builtin [ 'north' != 'south' ]; then echo 'what a world!'; fi
what a world!
Run Code Online (Sandbox Code Playgroud)
更新 2:
我认为还值得注意的是,经过一些挖掘和试验,我发现POSIX 标准和其他 Bourne 风格的 shell 在命令方面的zsh
行为完全相反command
。
来自zsh 文档(第 6.2 节,预命令修饰符)
命令 [-pvV]
命令字被视为外部命令的名称,而不是外壳函数或内置命令。
例如
$ echo ${ZSH_VERSION}
5.8
$ command cd ~
zsh: command not found: cd
$ command -p cd ~
zsh: command not found: cd
$ command echo 'hi'
hi
# `echo` is a regular builtin just like `cd` though...??!!!
$ set -o |grep posix
posixaliases off
posixargzero off
posixbuiltins off
posixcd off
posixidentifiers off
posixjobs off
posixstrings off
posixtraps off
$ cd() { echo 'I told you.'; }
$ cd
I told you.
# ????!!!!
Run Code Online (Sandbox Code Playgroud)
只有POSIX_BUILTINS
设置了环境变量(使用set -o posixbuiltins
),该命令才会command
执行特殊和常规的内置函数。
例如
$ echo ${ZSH_VERSION}
5.8
$ cd /
$ ls
bin dev home lib lib64 lost+found mnt proc run snap sys usr
boot etc init lib32 libx32 media opt root sbin srv tmp var
$ set -o posixbuiltins
$ command cd ~
$ ls
Desktop Downloads Pictures Templates
Documents Music Public Videos
$ command -p cd /
$ ls
bin dev home lib lib64 lost+found mnt proc run snap sys usr
boot etc init lib32 libx32 media opt root sbin srv tmp var
Run Code Online (Sandbox Code Playgroud)
另一方面,来自bash 文档
命令
命令 [-pVv]命令 [参数 ...]运行带有参数的命令,忽略任何名为 command 的 shell 函数。仅执行 shell 内置命令或通过搜索 PATH 找到的命令。
例如
$ bash --version
GNU bash, version 5.0.17(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2019 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
$ cd /
$ ls
bin dev home lib lib64 lost+found mnt proc run snap sys usr
boot etc init lib32 libx32 media opt root sbin srv tmp var
$ set +o posix # Turn off POSIX mode
$ command cd ~
$ ls
Desktop Downloads Pictures Templates
Documents Music Public Videos
$ command -p cd /
$ ls
bin dev home lib lib64 lost+found mnt proc run snap sys usr
boot etc init lib32 libx32 media opt root sbin srv tmp var
Run Code Online (Sandbox Code Playgroud)
所以zsh
表现得完全相反其他的Bourne风格的外壳相对于的command
命令......我开始厌恶zsh
越来越多...买家当心(买者自负)我想。
更新 3:
还值得注意的是ksh88
没有command
内置命令。这是在ksh93
. 要替换内置的ksh88
,您必须使用别名、函数和引用的尴尬组合。
(来源:Robbins、Arnold;Rosenblatt、Bill。学习 Korn Shell:Unix 编程(第 456 页)。O'Reilly 媒体。Kindle 版。)
这与@Gilles 'SO- 别作恶' 的回答一致。
POSIX的基本原理command
回答了您的问题的大部分历史方面。
\n\n该命令实用程序有点类似于第八版 shell内置命令,但由于命令也会进入文件系统来搜索实用程序,因此内置命令的名称并不直观。
\n
\n\n(\xe2\x80\xa6)添加命令 -v和-V选项是为了满足当前由三个不同的历史实用程序完成的用户需求:在 System V shell 中键入,在 KornShell 中键入,在 C 中键入壳。
\n
在第八版 sh中,builtin
内置函数被记录为只是绕过函数:
\n\n执行内置的特殊命令(例如break),无论定义的同名函数如何。
\n
别名还不存在(当它们出现时,有不同的机制可以绕过它们)。如果您想绕过某个函数来执行外部命令,您可以给出其完整路径,这样做的优点是可以准确指定您想要执行的内容,以防命令搜索路径上有多个具有该名称的可执行文件。命令的完整路径可能不同的系统间的可移植性并不是人们普遍关心的问题。builtin
确实无法用其他方式完成的一件事也是如此。
后来,POSIX 出现并添加了绕过函数的标准方法。在这种情况下,外部命令位于不同位置的系统的可移植性非常令人担忧,因此builtin
还不够,因此新command
的绕过函数(和别名,因为command foo
放置foo
在别名不扩展的位置)并找到标准命令。(今天 ksh 有一个名为 的内置命令builtin
,它执行完全不同的操作,但我不知道它是在 POSIX 创建之前还是之后出现command
。)但是,command
出于可移植性考虑,故意不跳过内置命令:如果sh 程序调用一个标准命令,操作系统可以选择是否将此命令作为内置命令提供。command
再次取消特殊内置函数的 \xe2\x80\x9cspecialbuiltin\xe2\x80\x9d 行为,以便应用程序不需要知道它是否正在调用内置函数。
我不知道为什么 zshcommand
在不在 POSIX 模式下时(特别是当选项posix_builtins
未设置时)会绕过内置函数。它当前的实现可以追溯到 1996 年 5 月zsh 2.6 beta 20command
中发布的更改(\xe2\x80\x9cremove -、exec、noglob 和保留字列表中的命令 \xe2\x80\x9d)。由于该实现已经对 POSIX 模式进行了不同的处理,我认为它是为了向后兼容早期版本的 zsh,但我没有进一步调查。这可能是故意的,因为如果未设置,内置命令不一定与 POSIX 兼容,因此如果应用程序使用特定的 POSIX 命令,最好不要调用它们。posix_builtins
command
归档时间: |
|
查看次数: |
94 次 |
最近记录: |