“/bin/[”到底是如何工作的?

“/bin/[”到底是如何工作的?

我总是很惊讶文件夹里/bin有一个[程序。

当我们做这样的事情时,这就是所谓的:if [ something ]

[通过在 shell 中显式调用该程序,它会要求相应的],当我提供右括号时,无论我在括号之间插入什么,它似乎都不会执行任何操作。

不用说,获得有关程序的帮助的通常方法不起作用,即既不起作用man [[ --help不起作用。

答案1

[命令的作用是评估测试表达式。它以 0 退出状态返回(这意味着真的)当表达式解析为 true 和其他值时(这意味着错误的) 否则。

并不是说它什么都不做,而是它的结果可以在其退出状态中找到。在 shell 中,您可以找到$?类似 Bourne shell 或$status大多数其他 shell (fish/rc/es/csh/tcsh...) 中最后一个命令的退出状态。

$ [ a = a ]
$ echo "$?"
0
$ [ a = b ]
$ echo "$?"
1

在其他语言中,例如perl,退出状态在以下返回值中返回system()

$ perl -le 'print system("[", "a", "=", "a", "]")'
0

请注意,所有现代的类似 Bourne 的 shell(和fish)都有一个内置[命令。通常只有当您使用另一个 shell 或执行诸如或或上面的命令之类/bin的操作时才会执行其中的命令...env [ foo = bar ]find . -exec [ -f {} ] \; -printperl

[命令也通过名称而为人所知test。当调用 as 时test,它不需要结束]论证。

虽然您的系统可能没有 的手册页[,但它可能有test.但再次请注意,它将记录/bin/[/bin/test实施。要了解[shell 中的内置函数,您应该阅读 shell 的文档。

有关该实用程序的历史以及与[[...]]ksh 测试表达式的差异的更多信息,您可能需要查看此其他问答请看这里

答案2

我总是很惊讶文件夹里/bin有一个[程序。

你感到惊讶是对的。这是罕见的 POSIX 命令之一,带有 null 实用程序 ( :),不遵守命令文件允许的字符约定(可移植文件名字符集)。

当我们做这样的事情时,这就是所谓的:if [ something ]

准确地说,但它可以不使用if也可以使用。

[通过在 shell 中显式调用该程序,它会要求相应的],当我提供右括号时,无论我在括号之间插入什么,它似乎都不会执行任何操作。

它没有做任何可见的事情,但实际上它所做的事情与与 一起使用时完全相同if,即将退出状态设置为 0 (true) 或其他任何值 (false),具体取决于您在括号内放入的内容。 (出于某种原因)它与test命令的行为相同;唯一的区别是它寻找结局]。看man test了解详情。

不用说,获得有关程序的帮助的通常方法不起作用,即既不起作用man [[ --help不起作用。

这取决于您的操作系统。man [在几个主流 Gnu/Linux 发行版上绝对适合我,但在 Solaris 上却不起作用。

[ --help可能有效或无效取决于实现,因为它无论如何都破坏了语法,缺少结尾]。此外,test/[命令的 POSIX 标准明确排除所有选项,包括--选项终止,因此 和 都[ --help ]需要test --help返回true并按设计保持沉默。请注意,括号内或之后的内容[以及看起来像选项的内容(例如-f file-n string等)并不是选项操作数

所有现代 Bourne 风格的 shell 解释器(例如bashkshdashzsh等)都将test/[实用程序作为内置函数在内部实现,因此当您使用它们时,要参考的正确手册页可能是 shell 的手册页,而不是 shell 的手册页test

在 Unix System III (1981) 之前,Bourne shell 没有将该test实用程序实现为内置程序,因此只能使用外部二进制命令实现。在 Unix System III 之前没有[命令(内部或内置),因此例如在 Unix Version 7 下您必须输入:

if test something ; then

代替:

if [ something ] ; then

答案3

[实际上更常见的是test命令。此命令的典型用途只是计算表达式并返回其条件 - true 或 false。它经常在if-then-else-fi语句中使用,尽管它可以在语句之外使用if,通过 shell&&||运算符有条件地运行其他命令,如下所示。

$ [ -e /etc/passwd  ] && echo "File exists"
File exists

$ test -e /etc/passwd && echo "File exists"
File exists

更具体地说,评估通过退出状态传达给其他命令。某些程序可能选择输出退出状态来表示不同类型的事件 - 程序成功完成、执行期间发生特定类型的错误或语法错误。在命令的情况下test,有0表示真、1表示假的情况。正如 Stephan 指出的,语法错误会产生2.

它的位置取决于您的系统,并且它还解释了为什么您在看到手册页时没有看到手册页man [。例如,在 FreeBSD 上它位于/bin.在 Linux 上(或者在我的特定情况下,Ubuntu 16.04)它是/usr/bin/.如果您在 Linux 系统上man [这样做,您将看到相同的文档打开。man test同样重要的是要注意,您的 shell 可能有自己的test.

还应该注意的是,该命令有问题,其中 Korn shell 的实现(俗称“条件表达式”带双方括号的引用,[[ "$USER" = "root" ]]) 寻求解决。此功能也被其他 shell 使用,例如bashzsh

答案4

[如果其参数中包含的表达式被视为 true,则命令返回退出状态零;如果其参数中包含的表达式被视为 false,则命令返回非零退出状态。如果它的最后一个参数不是,它也会失败并显示错误消息](这纯粹是出于美观原因)。

例如:

[ hello ]
echo "Exit-status of [ hello ] is:" $?
[ abc = abc ]
echo "Exit-status of [ abc = abc ] is:" $?
[ ]
echo "Exit-status of [ ] is:" $?
[ abc = def ]
echo "Exit-status of [ abc = def ] is:" $?

...将输出:

[ hello ] 的退出状态为:0      — 因为非空字符串被认为是 true
[ abc = abc ] 的退出状态为:0  — 因为 'abc' 确实与 'abc' 相同
[ ] 的退出状态为:1            — 因为空字符串被认为是 false
[ abc = def ] 的退出状态为:1  - 因为“abc”与“def”确实不同

然而,巴什在这些情况下,许多其他 shell 通常不会调用/bin/[(或/usr/bin/[),而是调用具有完全相同行为的内置命令(纯粹出于性能原因)。要调用/bin/[(不是 shell 内置代理),您需要显式指定其路径(例如/bin/[ hello ];虽然不需要使用]dirname 前缀 ☺),或者配置 shell 不使用内置代理(例如,enable -n [在bash中)。

PS:正如其他答案中所说,[test.但是test,与 不同的是[,不需要将]其作为最后一个参数(并且根本不希望有它;]test参数添加额外的内容可能会导致它失败并显示错误消息或返回错误的结果)/bin/test可以/bin/[解析为同一个文件(例如,一个是符号链接的;在这种情况下,行为转移可能是通过分析当前调用的命令test/[代码本身内)或不同的文件。对于test,shell 通常也调用内置代理,除非显式指定路径 ( /bin/test) 或者配置为不这样做 ( enable -n test)。

PPS:与test和不同[,modernif从来都不是真正的文件。它是 shell(例如 bash)语法的一部分:(if commandA; then commandB; fi可以使用换行符代替分号)commandB当且仅当commandA以零状态退出时才会执行。这完全适合testor的行为[,允许将它们组合起来if [ "$a" = foo ]; then …; fi (或者if test "$a" = foo; then …; fi- 只是可读性较差)。然而,现代脚本经常使用or[[代替,它(作为)从来都不是真正的文件,但始终是 shell 语法的一部分。test[if

PPPS:至于man——永远不要指望man有一篇文章介绍文件系统中的每个命令。有关某些(甚至是“真实的”、基于文件的)命令的信息可能会丢失,有关某些 shell 内置命令的信息可能不仅出现在专门针对特定 shell 的文章中(您肯定会在其中找到有关test[if, [[)。尽管如此,许多发行版都有明确的和man文章。 (关于,它没有被识别,原因很明显:它需要安静地处理类似的情况;在某些发行版上(不关闭)仍然显示帮助,在某些发行版上则不显示帮助。)test[--helptesta=--help; test "$a"[ --help]

相关内容