一个什么都不做的命令,只不过是一个注释引导,但实际上是一个内置的shell,它的目的是什么?

它比每次调用在脚本中插入注释要慢40%左右,这可能取决于注释的大小。我认为唯一可能的原因是:

# poor man's delay function
for ((x=0;x<100000;++x)) ; do : ; done

# inserting comments into string of commands
command ; command ; : we need a comment in here for some reason ; command

# an alias for `true'
while : ; do command ; done

我想我真正想要的是它在历史上的应用。


当前回答

我在一个脚本中看到了这种用法,并认为它可以很好地替代在脚本中调用basename。

oldIFS=$IFS  
IFS=/  
for basetool in $0 ; do : ; done  
IFS=$oldIFS  

... 这是替换代码:baseool =$(basename $0)

其他回答

我用它来轻松地启用/禁用变量命令:

#!/bin/bash
if [[ "$VERBOSE" == "" || "$VERBOSE" == "0" ]]; then
    vecho=":"     # no "verbose echo"
else
    vecho=echo    # enable "verbose echo"
fi

$vecho "Verbose echo is ON"

Thus

$ ./vecho
$ VERBOSE=1 ./vecho
Verbose echo is ON

这有助于编写干净的脚本。这不能用'#'完成。

同时,

: >afile

是保证'afile'存在但长度为0的最简单方法之一。

它类似于Python中的传递。

一种用法是将一个函数存根,直到它被写入:

future_function () { :; }

如果你想把一个文件截断为零字节,这对清除日志很有用,试试这个:

:> file.log

其他答案中没有提到的两个用法:

日志记录

以这个示例脚本为例:

set -x
: Logging message here
example_command

第一行set -x使shell在运行命令之前打印出该命令。这是一个非常有用的结构。缺点是通常的echo Log消息类型的语句现在打印两次消息。冒号方法避开了这个问题。请注意,您仍然必须转义特殊字符,就像您对echo所做的那样。

Cron职位名称

我看到它在cron作业中被使用,像这样:

45 10 * * * : Backup for database ; /opt/backup.sh

这是一个cron作业,每天在10:45运行脚本/opt/backup.sh。这种技术的优点是,当/opt/backup.sh打印一些输出时,它使电子邮件主题看起来更好看。

它对多语言程序也很有用:

#!/usr/bin/env sh
':' //; exec "$(command -v node)" "$0" "$@"
~function(){ ... }

现在这既是一个可执行的shell脚本,也是一个JavaScript程序:这意味着。/filename.js、sh filename.js和node filename.js都可以工作。

(这种用法确实有点奇怪,但还是很有效。)


请作一些说明:

Shell-scripts are evaluated line-by-line; and the exec command, when run, terminates the shell and replaces it's process with the resultant command. This means that to the shell, the program looks like this: #!/usr/bin/env sh ':' //; exec "$(command -v node)" "$0" "$@" As long as no parameter expansion or aliasing is occurring in the word, any word in a shell-script can be wrapped in quotes without changing its' meaning; this means that ':' is equivalent to : (we've only wrapped it in quotes here to achieve the JavaScript semantics described below) ... and as described above, the first command on the first line is a no-op (it translates to : //, or if you prefer to quote the words, ':' '//'. Notice that the // carries no special meaning here, as it does in JavaScript; it's just a meaningless word that's being thrown away.) Finally, the second command on the first line (after the semicolon), is the real meat of the program: it's the exec call which replaces the shell-script being invoked, with a Node.js process invoked to evaluate the rest of the script. Meanwhile, the first line, in JavaScript, parses as a string-literal (':'), and then a comment, which is deleted; thus, to JavaScript, the program looks like this: ':' ~function(){ ... } Since the string-literal is on a line by itself, it is a no-op statement, and is thus stripped from the program; that means that the entire line is removed, leaving only your program-code (in this example, the function(){ ... } body.)