(冒号)GNUBash内置的目的是什么?

(冒号)GNUBash内置的目的是什么?,bash,shell,built-in,Bash,Shell,Built In,一个命令什么也不做,只是一个注释引导者,但实际上是一个内置的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 i

一个命令什么也不做,只是一个注释引导者,但实际上是一个内置的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' (lazy programming)
while : ; do command ; done
#穷人的延迟功能

对于((x=0;x历史上的,Bourne shells没有
true
false
作为内置命令。
true
被简单地别名为
,而
false
类似于
let 0

>代码> <>代码> Trime。对于一个简单的例子,考虑到既没有<代码> < /> >流水线运算符,也没有<代码> > <代码>列表操作符(如一些古贝壳的情况)。这使得

if
语句的
else
子句成为基于退出状态进行分支的唯一方法:

if command; then :; else ...; fi
由于
如果
需要一个非空
,那么
子句和注释不算为非空,
用作禁止操作

如今(即:在现代语境中)通常可以使用
true
。两者都是由POSIX指定的,有些人认为
true
更容易阅读。但是有一个有趣的区别:
是所谓的POSIX特殊内置,而
true
是常规内置

  • 需要在shell中内置特殊的内置程序;常规的内置程序只是“典型”的内置程序,但没有严格的保证。在大多数系统的路径中,通常不应该有一个名为
    且具有
    true
    功能的常规程序

  • 可能最关键的区别在于,对于特殊的内置,内置设置的任何变量(即使在简单命令求值期间的环境中)在命令完成后仍然存在,如使用ksh93所示:

    $ unset x; ( x=hi :; echo "$x" )
    hi
    $ ( x=hi true; echo "$x" )
    
    $
    
    请注意,Zsh忽略了这一要求,GNUBASH也忽略了这一要求,但在POSIX兼容模式下运行时除外,但所有其他主要的“POSIX sh派生”shell都遵守这一要求,包括dash、ksh93和mksh

  • 另一个区别是,常规内置必须与
    exec
    兼容-这里使用Bash演示:

    $ ( exec : )
    -bash: exec: :: not found
    $ ( exec true )
    $
    
  • POSIX还明确指出,
    可能比
    true
    更快,当然这是一个特定于实现的细节


您可以将其与反勾号(
`
)结合使用来执行命令,而不显示其输出,如下所示:

: `some_command`
45 10 * * * : Backup for database ; /opt/backup.sh
#!/usr/bin/env sh
':' //; exec "$(command -v node)" "$0" "$@"
':'
~function(){ ... }
当然,您可以只执行
一些命令>/dev/null
,但是
-版本稍微短一些


尽管如此,我不建议实际这样做,因为这只会让人感到困惑。它只是作为一个可能的用例出现在我的脑海中。

它类似于Python中的
pass

一种用途是在函数被写入之前将其存根:

future_function () { :; }

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

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

$vecho "Verbose echo is ON"
因此

这使得脚本干净。这不能用“#”完成

而且


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

对于
来说,一个有用的应用程序是,如果您只对参数扩展的副作用感兴趣,而不是实际将其结果传递给命令

在这种情况下,您可以使用参数展开作为
false
的参数,具体取决于您想要的退出状态是0还是1

: "${var:=$1}"

由于
是一个内置的,它应该非常快。

如果您想将文件截断为零字节,这对清除日志非常有用,请尝试以下操作:

:> file.log

也可以用于块注释(类似于C语言中的/**/)。例如,如果要跳过脚本中的一块代码,可以执行以下操作:

: << 'SKIP'

your code block here

SKIP

:其他答案中未提及的另外两个用途:

登录中 以这个脚本为例:

set -x
: Logging message here
example_command
第一行,
set-x
,使shell在运行命令之前打印出命令。这是一个非常有用的构造。缺点是,通常的
echo Log message
类型的语句现在会打印两次消息。冒号方法解决了这一问题。请注意,您仍然需要像对或
echo

Cron职务 我看到它被用于cron作业,如下所示:

: `some_command`
45 10 * * * : Backup for database ; /opt/backup.sh
#!/usr/bin/env sh
':' //; exec "$(command -v node)" "$0" "$@"
':'
~function(){ ... }

这是一个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
,和
节点filename.js
都可以工作

(肯定有点奇怪,但仍然有效。)


应要求进行一些解释:

  • Shell脚本逐行计算;
    exec
    命令在运行时终止Shell并用结果命令替换其进程。这意味着对于Shell,程序如下所示:

    : `some_command`
    
    45 10 * * * : Backup for database ; /opt/backup.sh
    
    #!/usr/bin/env sh
    ':' //; exec "$(command -v node)" "$0" "$@"
    
    ':'
    ~function(){ ... }
    
  • 只要单词中没有出现参数扩展或别名,shell脚本中的任何单词都可以用引号括起来,而不改变其“含义”;这意味着
    :”
    等同于
    (我们在这里只用引号括起来,以实现下面描述的JavaScript语义)

  • …如上所述,第一行的第一个命令是no op(它转换为
    ://
    ,或者如果您喜欢引用