内置的冒号 ':' 有什么作用?

Cal*_*leb 49 shell-script shell-builtin

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

文档似乎很简单:

: (a colon)  
     : [arguments]  
Run Code Online (Sandbox Code Playgroud)

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

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

if [ -f ${file} ]; then
    grep some_string ${file} >> otherfile || :
    grep other_string ${file} >> otherfile || :
fi
Run Code Online (Sandbox Code Playgroud)

实际上有数百个 grep,但它们只是更多相同。除了上面的简单结构之外,不存在输入/输出重定向。稍后在脚本中不会检查返回值。

我正在阅读这是一个无用的结构,上面写着“或什么都不做”。用“或什么都不做”来结束这些 grep 的目的是什么?在什么情况下,这个构造会导致与简单地|| :从所有实例中删除不同的结果?

Jon*_*oni 47

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

# assign FOO=bar iff FOO is unset or empty
: "${FOO:=bar}"
Run Code Online (Sandbox Code Playgroud)

  • 来到这里寻找这个,当我在脚本中看到这个模式来声明默认值时感到困惑。 (4认同)

Kev*_*vin 31

看来:脚本中的s 正在代替true. 如果grep在文件中没有找到匹配项,它将返回一个非零退出代码;正如 jw013 在评论中提到的,如果errexit设置了,可能是-e在 shebang 行上,如果任何greps 未能找到匹配项,脚本将退出。显然,这不是作者想要的,所以 (s) 他添加|| :了使该特定复合命令的退出状态始终为零,就像更常见的(根据我的经验)|| true/ || /bin/true

  • 如果是这种情况,我会称其为糟糕的脚本编写实践。它在功能上等同于使用 `true`,但使用 `true` 的语义意图更加清晰。`:` 在需要明确的 NOP 时更合适。 (9认同)

Gil*_*il' 25

:内置已经在汤普森壳-它记录Unix的V6于1975年在汤普森的外壳,:显示了一个标签goto命令。如果您从未尝试调用goto以 开头的行,则该行实际上是一条注释。

Bourne shell中,伯恩/ POSIX壳的祖先,因为我们知道他们,从未有过的goto,我知道的,但保留:为空操作命令(它已经存在于Unix的V7),并且它通常用于评论(实际的注释语法 with#仅在更高版本中添加)。


Bru*_*ger 24

我能想到我过去用过的两个地方:

while :
do
     shell commands
     some exit condition
done
Run Code Online (Sandbox Code Playgroud)

那是一个永远的循环。

function doSomethingStub {
    :
}
Run Code Online (Sandbox Code Playgroud)

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

我在过去见过的一种用法:#!/bin/sh您会看到一条:线,而不是一条(或其他任何)线。一些较旧的 Real Unix 内核或 Real Unix shell 会使用它来表示“我是一个 shell 脚本,让 sh 运行我”。我记得这正是 csh 作为通用交互式 shell 取得进展的时候。请参阅:http : //www.faqs.org/faqs/unix-faq/faq/part3/section-16.html

  • 终于找到了“:在脚本开头”的参考和解释:http://www.faqs.org/faqs/unix-faq/faq/part3/section-16.html (8认同)

小智 18

我翻出了一个旧的参考资料:Kernighan 和 Pike 于 1984 年出版的“The UNIX Programming Environment”(c)。

第 147 页(Shell Programming)说:

":" 是一个 shell 内置命令,它除了计算它的参数并返回 "true" 之外什么都不做。相反[参考脚本示例],我们可以使用true,它只返回一个真正的退出状态。(还有一个false命令。)但是 ':' 比 true 更有效率,因为它不执行来自文件系统的命令。[斜体/强调是我的。]

  • 当然,在许多系统上,`true` 现在也是内置的 shell。 (3认同)

Col*_*lin 13

":" 便于调试。

DEBUGLOG=": debugfunction"

statement
statement
$DEBUGLOG arg1 arg2 ...
statement
statement
Run Code Online (Sandbox Code Playgroud)

正常运行时,调试函数永远不会执行,所以 sh 只是跳过 noop(尽管变量和通配符被扩展)。如果需要更深入的调试,请从变量中删除 noop,并使用所需的任何参数调用 debugfunction。

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

: << COMMENT
all --statements --in --here
are now -a here document which are
passed to --the noop
COMMENT
Run Code Online (Sandbox Code Playgroud)


Kei*_*son 10

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

这是古代Thompson shell手册页(没有关系);没有提到任何注释语法。

  • `:` 的起源实际上是 `goto` 命令的标签指示符,在一些古老的 shell 中(我不知道是哪个)。如果没有匹配的 `goto`,标签 `: something` 确实可以用作注释。即使在“goto”消失后,这种做法仍然存在。 (5认同)