bash 多行命令在连续字符后带有注释

Fah*_*tha 42 shell bash

考虑

echo \ # this is a comment
foo
Run Code Online (Sandbox Code Playgroud)

这给出:

$ sh foo.sh
 # this is a comment
foo.sh: line 2: foo: command not found
Run Code Online (Sandbox Code Playgroud)

在网上搜索后,我在姊妹网站 Stack Overflow 上找到了DigitalRoss解决方案。所以一个人可以做

echo `: this is a comment` \
foo
Run Code Online (Sandbox Code Playgroud)

或者

echo $(: this is a comment) \
foo
Run Code Online (Sandbox Code Playgroud)

但是,DigitalRoss 没有解释为什么这些解决方案有效。我很感激解释。他回复了一条评论:

曾经有一个 shellgoto命令分支到指定的标签,如:这里。该goto走了,但你仍然可以使用的 : whatever语法...:是一种解析的评论了。

但我想要更多细节和上下文,包括对可移植性的讨论。

当然,如果有人有其他解决方案,那也很好。

另请参阅较早的问题如何在 shell 脚本中注释多行命令?.


从下面的讨论中获取信息。这`: this is a comment`只是一个命令替换。的输出: this is a comment什么都没有,它被放在了 的位置`: this is a comment`

更好的选择如下:

echo `# this is a comment` \
foo
Run Code Online (Sandbox Code Playgroud)

Gil*_*il' 32

注释在第一个换行符结束(参见shell 标记识别规则 10),不允许继续行,因此此代码foo在单独的命令行中:

echo # this is a comment \
foo
Run Code Online (Sandbox Code Playgroud)

至于你的第一个提议,反斜杠后面没有换行符,你只是引用了空格:它相当于

echo ' # this is a comment'
foo
Run Code Online (Sandbox Code Playgroud)

$(: this is a comment)替换命令的输出: this is a comment。如果该命令的输出为空,这实际上是在行中间插入注释的一种非常容易混淆的方式。

没有什么魔法在发生::是一个普通的命令,冒号实用程序,它什么都不做。当 shell 语法需要命令但您恰好无事可做时,冒号实用程序最有用。

# Sample code to compress files that don't look compressed
case "$1" in
  *.gz|*.tgz|*.bz2|*.zip|*.jar|*.od?) :;; # the file is already compressed
  *) bzip2 -9 "$1";;
esac
Run Code Online (Sandbox Code Playgroud)

另一个用例是用于设置尚未设置的变量的习惯用法。

: "${foo:=default value}"
Run Code Online (Sandbox Code Playgroud)

关于 goto 的评论是历史性的。冒号实用程序甚至可以追溯到Bourne shell之前,一直到Thompson shell,它有一个goto指令。冒号则表示标签;冒号是 goto 标签的一种相当常见的语法(它仍然存在于sed 中)。

  • @FaheemMitha 正如您引用的线程中所建议的那样:将您的命令分解为可管理的块并评论每个块。如果你的命令太复杂以至于需要在中间添加注释,那么是时候简化它了! (3认同)
  • 嗯,有问题的命令有很多参数......它正在将一堆视频文件转换为一个文件。我没有看到简化它的直接方法。也许创建某种列表,并将其作为参数传递?我想这可能是另一个问题。 (2认同)

小智 12

您可以使用 Bash 数组来实现这一点,例如

#!/bin/bash
CMD=(
  echo  # this is a comment
  foo
  )

"${CMD[@]}"
Run Code Online (Sandbox Code Playgroud)

这定义了一个数组,$CMD然后扩展它。一旦展开,结果行就会被评估,所以在这种情况下会echo foo被执行。

(和之间的文本)定义了数组,并受制于通常的 bash 语法,因此后面一行中的所有内容都将#被忽略。

关于保留引用空格的注意事项

${CMD[@]}扩展为单个字符串,它是所有元素的串联,由空格分隔。一旦展开,Bash 就会以通常的方式(cf $IFS)将字符串解析为标记,这通常不是我们想要的。

相比之下,如果扩展用双引号括起来,即"${CMD[@]}",则数组中的每个元素都被保留。考虑之间的差异hello world second item"hello world" "second item"

说明性示例:

# LIST=("hello world" "second item")

# for ITEM in ${LIST[@]}; do echo $ITEM; done
hello
world
second
item

# for ITEM in "${LIST[@]}"; do echo $ITEM; done
hello world
second item
Run Code Online (Sandbox Code Playgroud)


mik*_*erv 8

不要做$(: comment)。这不是评论——这是一个子shell——大多数shell的另一个全新的shell进程。你的目标是用你的输入做更少的事情,而不是更多,这就是这样做的 - 即使它毫无意义。

你可以做...

printf '<%s>\n' some args here ${-##*"${--

                my long comment block

                }"}  and "more ${-##*"${--

                and another one in the
                middle of the quoted string
                there shouldn\'t b\e any special &
                (character) `echo issues here i hope >&2`
                basically anything that isn\'t a close \}
                $(echo the shell is looking for one >&2)
                }$(echo "}'"\" need backslash escaping >&2
                                )${-##*${--

                nesting is cool though

             }}"}here too"
Run Code Online (Sandbox Code Playgroud)
printf '<%s>\n' some args here ${-##*"${--

                my long comment block

                }"}  and "more ${-##*"${--

                and another one in the
                middle of the quoted string
                there shouldn\'t b\e any special &
                (character) `echo issues here i hope >&2`
                basically anything that isn\'t a close \}
                $(echo the shell is looking for one >&2)
                }$(echo "}'"\" need backslash escaping >&2
                                )${-##*${--

                nesting is cool though

             }}"}here too"
Run Code Online (Sandbox Code Playgroud)

基本上发生的事情是外壳正在进行替换。它$-每次替换特殊 shell 参数的值两次。无论如何它都是一个短字符串,但它总是被设置 - 因此内部替换 - 被解释为从外部剥离的模式 -当我使用扩展形式时不会扩展到括号​​之间的内容-

这里:

bash -x <<""
printf %s\\n '${-##*"'${-- a set param doesn\'t expand to this optional text }'"}'
Run Code Online (Sandbox Code Playgroud)
}'" need backslash escaping
<some>
<args>
<here>
<and>
<more here too>
Run Code Online (Sandbox Code Playgroud)

See? So it's just expanded twice. As soon the shell finds the parameter is set everything in the optional expansion field is discarded, pretty much, and it expands to its whole value which is removed from itself and so to nothing at all. In most shells you need not even escape quotes, but bash requires it.

Better still is:

COMMENT=
echo      ${COMMENT-"
           this will work the same way
           but the stripping isn\'t
           necessary because, while
           the variable is set, it is also
           empty, and so it will expand to
           its value - which is nothing
           "} this you\'ll see
Run Code Online (Sandbox Code Playgroud)
this you'll see
Run Code Online (Sandbox Code Playgroud)