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


29

考虑

echo \ # this is a comment
foo

这给出:

$ sh foo.sh
 # this is a comment
foo.sh: line 2: foo: command not found

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

echo `: this is a comment` \
foo

或者

echo $(: this is a comment) \
foo

但是,DigitalRoss没有解释这些解决方案为何起作用。我希望得到一个解释。他回答说:

以前有一个shell goto命令,它会分支到:此处指定的标签。该goto走了,但你仍然可以使用的 : whatever语法... :是一种解析的评论了。

但我想要更多细节和背景信息,包括可移植性的讨论。

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

另请参见前面的问题如何在Shell脚本中注释多行命令?


从下面的讨论中带回家的消息。该`: this is a comment`只是一个命令替换。的输出: this is a comment为空,它将代替`: this is a comment`

更好的选择如下:

echo `# this is a comment` \
foo

Answers:


25

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

echo # this is a comment \
foo

对于您的第一个建议,反斜杠后没有换行符,您只引用了空格:它等效于

echo ' # this is a comment'
foo

$(: 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

另一个用例是用于设置变量(如果尚未设置)的惯用法。

: "${foo:=default value}"

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


好的我明白了。您知道在此上下文中插入注释的任何一种更好的方法吗?
Faheem Mitha

3
@FaheemMitha正如您在线程中所建议的:将命令分解为可管理的块并注释每个块。如果您的命令太复杂以至于需要在中间添加注释,那么该是时候对其进行简化了!
吉尔(Gilles)'所以

1
嗯,所讨论的命令有很多参数……它将一堆视频文件转换为一个文件。我看不到直接简化它的方法。也许创建某种列表,并将其作为参数传递?我想那可能是另一个问题。
Faheem Mitha

@FaheemMitha示例:make_FIND,一个快速脚本,可为生成一长串参数find。在这里,逐块构建它的动机是每个块都来自循环的主体,但是相同的样式允许对每个块进行注释。
吉尔(Gilles)'所以

1
谢谢你的例子。我的示例基本上只是一长串作为命令参数提供的名称。我希望每个名称都附有评论,因为这是保持上下文的最简单方法。我没有看到任何明显的方法可以将命令分解为多个部分,如果这样做,它可能会使它更长,并且已经足够长了。
Faheem Mitha

6

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

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

"${CMD[@]}"

这将定义一个数组,$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

感谢您的回答,@ RobM。因此,您的建议是在bash数组本身中包含有关列表中项目的注释/元信息?如果我提供了我尝试使用的命令类型的示例,则该问题可能会更有用。我不知道为什么我没有。
Faheem Mitha 2015年

ah,事实证明我没有仔细阅读您的问题。以为您在问与您链接的问题。哎呀。:)
RobM

${CMD[@]}不会扩展为单个字符串。–它扩展为许多字符串:不仅为数组的每个元素拆分,而且还在每个元素的空格中拆分。(即:完全没用)
罗伯·西默

4

不要做$(: 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"

}'" need backslash escaping
<some>
<args>
<here>
<and>
<more here too>

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

这里:

bash -x <<""
printf %s\\n '${-##*"'${-- a set param doesn\'t expand to this optional text }'"}'

+ printf '%s\n' '${-##*"hxB"}'
${-##*"hxB"}

看到?因此,它只扩展了两次。一旦外壳程序发现参数已设置,则可选扩展字段中的所有内容都会被丢弃,并且几乎扩展,并且扩展到其整个值,该值会从自身中删除,因此什么也没有。在大多数shell中,您甚至不需要转义引号,但bash需要它。

更好的是:

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

this you'll see
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.