如果显式地不执行任何操作,那么::命令在shell脚本中的用途是什么?


27

这个有关shell脚本中注释的问题的答案,表明:a是一个空命令,显式不执行任何操作(但不用于注释)。

什么也不做的命令的效用是什么?



2
另请参阅此问题这里有一个更好的答案,即必须:是内置的,而true不是,这会影响变量的范围
Old Pro

2
它明确地没有优雅地执行任何操作。
mikeserv

Answers:


19

我通常true在循环中使用;我认为更清楚:

while true; do
    ...
done

我发现一个:真正方便的地方是case语句,如果您需要匹配某些内容但又不想实际做任何事情。例如:

case $answer in
    ([Yy]*) : ok ;;
    (*)     echo "stop."; exit 1 ;;
esac

3
我同意。 true对于一个条件,:对于一个NOP。
2012年

1
bash接受case a in a ) ;; esac。有没有不接受这个的贝壳?
2012年

@Kaz:根据POSIX shell语法case ${var} in value);; *) do_something;; esac是可以接受的。:空情况下不需要此命令。
理查德·汉森

12

最初,它是用来确定它是Bourne shell程序,而不是C编译程序。这是在shebang和多种脚本语言(csh,perl)之前。您仍然可以运行仅以:以下内容开头的脚本:

$ echo : > /tmp/xyzzy
$ chmod +x /tmp/xyzzy
$ ./xyzzy

通常,它将针对$SHELL(或/bin/sh)运行脚本。

从那时起,主要用途是评估参数。我仍然使用:

: ${EDITOR:=vim}

在脚本中设置默认值。


11

: 对于编写必须从内部终止的循环很有用。

while :
do
    ...stuff...
done

除非调用break或被exit调用,否则shell 将永远运行,否则shell会收到终止信号。


3
我觉得while true; do ...; done与读者交流意图要好于while :; do ...; done
理查德·汉森

9

如果您希望在shell脚本中使用“除非”语句,则可以使用“不”条件(对于某些测试可能看起来很愚蠢),也可以在真句中使用“:”,在假句中使用真实代码,条款。

if [ some-exotic-condition ]
then
    :
else
    # Real code here
fi

“异国情调”可能是您不想否定的东西,或者,如果您不使用“负逻辑”,那就更清楚了。


1
它也显示在生成的脚本中,autoconf因为:为空分支添加默认值比找出如何反转条件要容易得多。
Dietrich Epp 2012年

2
我看不到粘在!前面[ some-exotic-condition ]是多么愚蠢,但是多余的: else东西却不是愚蠢的。
卡兹(Kaz)

@Kaz有一个好点。让我们记住,充其量是很难的。如果您必须否定所有这些,那是一回事,但这可能会使情况变得不太清楚。做'!' 否定整个条件,还是只考虑第一个条件?有时最好有一个':'true子句。
布鲁斯·埃迪格

!令牌使整个命令管道元素无效。 while ! grep ... ; do ... doneif ! [ ... ] ; then ... fi。它基本上在test/[]语法外部。参见:pubs.opengroup.org/onlinepubs/9699919799/utilities/…–
Kaz

5

由于shell语法中不允许有空命令序列的缺陷,在这种情况下,注释掉该行会产生语法错误,因此我只在#字符之外使用过此字符来暂时注释掉一行:

if condition ; then
    :# temporarily commented out command
fi

没有:,我们缺少命令序列,这是语法错误。


4

我发现有两种情况:有用:

默认变量分配

#!/bin/sh

# set VAR to "default value" if not already set in the environment
: "${VAR=default value}"

# print the value of the VAR variable.  Note that POSIX says the behavior
# of echo is implementation defined if the first argument is '-n' or if any
# argument contains a '\', so use printf instead of echo.
printf '%s\n' "VAR=${VAR}"

这是允许Shell脚本用户覆盖设置而无需编辑脚本的便捷方法。(但是,命令行参数更好,因为如果用户恰巧拥有在其导出环境中使用的变量,则不会冒意外行为的风险。)这是用户将覆盖设置的方式:

VAR="other value" ./script

${VAR=value}语法说要集VARvalue如果VAR尚未设置,然后展开对变量的值。由于我们现在还不在乎变量的值,因此将其作为参数传递给no-op命令:以将其丢弃。

即使:是no-op命令,也要:在运行:命令之前由外壳程序(而不是命令!)执行扩展,因此仍会发生变量分配(如果适用)。

使用true或其他命令代替也是可以接受的:,但是由于意图不明确,因此代码变得更难阅读。

以下脚本也可以使用:

#!/bin/sh

# print the value of the VAR variable.  Note that POSIX says the behavior
# of echo is implementation defined if the first argument is '-n' or if any
# argument contains a '\', so use printf instead of echo.
printf '%s\n' "VAR=${VAR=default value}"

但是,上面的内容很难维护。如果在该行${VAR}上方添加了using printf行,则必须移动默认分配扩展。如果开发人员忘记移动该任务,则会引入错误。

放在空的条件块中的东西

通常应避免使用空条件块,但有时它们很有用:

if some_condition; then
    # todo:  implement this block of code; for now do nothing.
    # the colon below is a no-op to prevent syntax errors
    :
fi

有人认为,空的true if块比否定测试更容易阅读代码。例如:

if [ -f foo ] && bar || baz; then
    :
else
    do_something_here
fi

可以说比以下内容更容易阅读:

if ! [ -f foo ] || ! bar && ! baz; then
    do_something_here
fi

但是我相信有一些替代方法比空的真实块更好:

  1. 将条件放入函数中:

    exotic_condition() { [ -f foo ] && bar || baz; }
    
    if ! exotic_condition; then
        do_something_here
    fi
    
  2. 否定条件之前,将条件放在花括号(或括号,但括号内会产生一个子shell进程,并且对该子shell内的环境所做的任何更改在该子shell外部均不可见)。

    if ! { [ -f foo ] && bar || baz; } then
        do_something_here
    fi
    
  3. 使用||代替if

    [ -f foo ] && bar || baz || {
        do_something_here
    }
    

    当反应是简单的单线反应时(例如声明条件),我更喜欢这种方法:

    log() { printf '%s\n' "$*"; }
    error() { log "ERROR: $*" >&2; }
    fatal() { error "$@"; exit 1; }
    
    [ -f foo ] && bar || baz || fatal "condition not met"
    

1

在古老的UNIX版本中,旧的pre-bourne shell中,该:命令最初是用于指定标签的goto(这是一个单独的命令,它将输入绕到找到标签的位置,因此标签不能是shell知道。if它也是一个单独的命令。)在有注释语法(#用于退格键)之前,它很快就用于注释了,这些天来几乎是兼容的。


0

除了将其用作不执行任何操作的语句外,您还可以使用它通过将单个语句变成:的参数来注释掉单个语句。


这将不是完全的注释,因为: echo write this line > myfile仍会创建一个空文件。
Arcege 2012年

5
如问题链接中所述,:不是适当的评论机制。
2012年
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.