: 命令在 shell 脚本中的用途是什么,因为它明确地什么都不做?

DQd*_*dlM 27 shell shell-script

关于 shell scripting 中的注释的这个问题的答案,表明:是一个空命令,它明确地不做任何事情(但不用于注释)。

一个什么都不做的命令有什么用?

Mad*_*ist 20

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

while true; do
    ...
done
Run Code Online (Sandbox Code Playgroud)

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

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

  • 我同意。`true` 表示条件,`:` 表示 NOP。 (3认同)

Arc*_*ege 13

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

$ echo : > /tmp/xyzzy
$ chmod +x /tmp/xyzzy
$ ./xyzzy
Run Code Online (Sandbox Code Playgroud)

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

从那时起,主要用途是评估参数。我还在用:

: ${EDITOR:=vim}
Run Code Online (Sandbox Code Playgroud)

在脚本中设置默认值。


Kyl*_*nes 11

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

while :
do
    ...stuff...
done
Run Code Online (Sandbox Code Playgroud)

这将永远运行,除非breakexit被调用,或者外壳收到终止信号。

  • 我觉得`虽然是真的; 做 ...; done` 比 `while :; 更能向读者传达意图。做 ...; 完成` (4认同)

Bru*_*ger 10

当您需要在 shell 脚本中使用“除非”语句时,您可以使用“not”条件,这对于某些测试来说可能看起来很愚蠢,或者您在 true 子句中使用 ':',在 false 中使用真实代码 -条款。

if [ some-exotic-condition ]
then
    :
else
    # Real code here
fi
Run Code Online (Sandbox Code Playgroud)

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

  • 我看不出在 `[ some-exotic-condition ]` 前面插入一个 `!` 是多么愚蠢,但是在它之后插入一个多余的 `:else` 就不是愚蠢了。 (3认同)

Kaz*_*Kaz 9

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

if condition ; then
    :# temporarily commented out command
fi
Run Code Online (Sandbox Code Playgroud)

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


Ric*_*sen 6

我觉得有两种情况:很有用:

默认变量赋值

#!/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}"
Run Code Online (Sandbox Code Playgroud)

这是一种方便的方式,允许您的 shell 脚本用户在不编辑脚本的情况下覆盖设置。(但是,命令行参数更好,因为如果用户巧合地拥有您在其导出环境中使用的变量,您不会冒意外行为的风险。)以下是用户将如何覆盖设置:

VAR="other value" ./script
Run Code Online (Sandbox Code Playgroud)

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

即使:是一个无操作命令,:在运行:命令之前,扩展是由 shell(而不是命令!)执行的,因此变量分配仍然发生(如果适用)。

也可以使用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}"
Run Code Online (Sandbox Code Playgroud)

但是上面的维护起来要困难得多。如果在该行${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
Run Code Online (Sandbox Code Playgroud)

有些人认为,if与否定测试相比,拥有一个空的 true块可以使代码更易于阅读。例如:

if [ -f foo ] && bar || baz; then
    :
else
    do_something_here
fi
Run Code Online (Sandbox Code Playgroud)

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

if ! [ -f foo ] || ! bar && ! baz; then
    do_something_here
fi
Run Code Online (Sandbox Code Playgroud)

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

  1. 将条件放入函数中:

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

    if ! { [ -f foo ] && bar || baz; } then
        do_something_here
    fi
    
    Run Code Online (Sandbox Code Playgroud)
  3. 使用||代替if

    [ -f foo ] && bar || baz || {
        do_something_here
    }
    
    Run Code Online (Sandbox Code Playgroud)

    当反应是简单的单行时,我更喜欢这种方法,例如断言条件:

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