内置的冒号有什么作用?


44

我已经破解了许多shell脚本,有时最简单的事情使我感到困惑。今天,我遇到了一个脚本,该脚本大量使用了:内置的(冒号)bash。

documenation似乎很简单:

: (a colon)  
     : [arguments]  

除了扩展参数和执行重定向之外,什么也不要做。返回状态为零。

但是,我以前仅在用于shell扩展的演示中看到过这种用法。我遇到的脚本中的用例广泛使用了此结构:

if [ -f ${file} ]; then
    grep some_string ${file} >> otherfile || :
    grep other_string ${file} >> otherfile || :
fi

实际上有几百个抱怨,但更多的是相同的。除了上面的简单结构之外,没有输入/输出重定向。稍后在脚本中不检查返回值。

我将其视为无用的构造体,上面写着“或者什么也不做”。以“或什么都不做”来结束这些抱怨有什么目的?在什么情况下,这种构造会导致与简单地|| :从所有实例中删除结果不同的结果?


10
我可以看到的一个可能目的是:替代true。也许errexit已经设置好了,作者并不关心某些命令的退出状态。
jw013


Stackoverflow链接页面使IMO更加全面(阅读此页面和链接页面非常好)。
Trevor Boyd Smith

Answers:


29

似乎:您的脚本中的s被用来代替true。如果grep在文件中找不到匹配项,它将返回一个非零的退出代码;正如jw013在评论中提到的那样,如果errexit设置了(可能是-e在shebang行上),则如果任何greps无法找到匹配项,脚本将退出。显然,这不是作者想要的,因此他添加|| :了该复合命令,使其退出状态始终为零,就像更常见的(以我的经验)|| true/一样|| /bin/true


咄。这是RPM构建脚本的概念,尽管我没有在脚本中看到任何退出代码检查,但我忘记考虑父进程可能正在监视。
Caleb '02

8
如果是这样,我会称其为不良的脚本编写实践。从功能上讲,它等效于使用true,但使用可以使语义更清晰true:当需要显式的NOP时更适合
jw013 2012年

以我的经验,这是RPM脚本中的常见做法。它可能不应该,但是我们存在。
mattdm

一些纯粹主义者更喜欢:而不是true因为:它是bash内置的,true通常是编译后的二进制文件,具有更多的开销。通常,我使用true代码是因为代码更具可读性(同样,我更喜欢使用source而不是.)。
Trevor Boyd Smith

36

:内置也与打击“分配默认值”壳膨胀,其中所述膨胀通常仅用于副作用和膨胀值被扔掉有用:

# assign FOO=bar iff FOO is unset
: ${FOO:=bar}

2
来到这里寻找时,当我在脚本中看到此模式以声明默认值时感到困惑。
2015年

20

我可以想到我过去使用:过的两个地方。

while :
do
     shell commands
     some exit condition
done

那是一个永远的循环。

function doSomethingStub {
    :
}

放入存根函数,只是为了获得正确的顶级控制流。

我在过去曾经见过的一种用法:#!/bin/sh您会看到一条:线,而不是(或任何其他)行。一些较早的Real Unix内核或Real Unix shell会使用它来表示“我是shell脚本,请让我运行”。我记得这只是csh成为通用交互式shell的时候。


@BruceEdiger:您是否提到“ shecolon”这一行?
l0b0 2012年

7
终于找到了“:在脚本开头”的参考和解释:faqs.org/faqs/unix-faq/faq/part3/section-16.html
Bruce Ediger

1
一开始的行为:很奇怪。我发现它确实导致脚本与一起运行sh。在那里,当您启动脚本没有认领......尝试运行与任何shell运行(所以如果你正在运行的脚本,bash它试图以运行它bash,如果你有csh那么它试图运行它csh)。
Trevor Boyd Smith


11

我挖了一个旧的参考文献:Kernighan和Pike撰写的“ UNIX编程环境”(c)1984。

页面147(Shell编程)说:

“:”是shell内置命令,除了评估其参数并返回“ true”外,不执行任何操作。代替[参考脚本示例],我们可以使用true,它仅返回true退出状态。(还有一条错误的命令。)但是':'比true更有效,因为它不执行来自文件系统的命令。[斜体/重点是我的。]


2
当然,true现在在许多系统上也是内置的shell。
点钟

8

我似乎记得,早期版本的Shell没有注释语法。以:(可能是实际的可执行文件,类似于/bin/true)开头的行将是最佳选择。

这是古老的汤普森贝壳手册页(没有关系);没有提及任何注释语法。


4
:实际上,它的起源是goto命令的标签指示符,在某些古老的外壳中(我不知道是哪个)。: something如果没有匹配项,则确实可以将标签用作注释goto。即使goto消失了,这种做法仍然停滞不前。
吉尔(Gilles)'所以

8

“:”方便调试。

DEBUGLOG=": debugfunction"

statement
statement
$DEBUGLOG arg1 arg2 ...
statement
statement

正常运行调试功能永远不会执行,因此仅步过noop(尽管变量和通配符已扩展)。如果需要进行更深入的调试,请从变量中删除noop,并使用所需的任何参数调用debugfunction。

另一个方便的用法是用作块注释,这是Shell语法缺少的功能。

: << COMMENT
all --statements --in --here
are now -a here document which are
passed to --the noop
COMMENT
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.