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

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

考虑

echo \ # this is a comment
foo

这给出:

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

经过一番网上搜索,我发现了一个DigitalRoss 的解决方案在姊妹网站 Stack Overflow 上。所以一个人可以做

echo `: this is a comment` \
foo

或者替代地

echo $(: this is a comment) \
foo

然而,DigitalRoss 没有解释这些解决方案为何有效。我希望得到解释。他回复了评论:

曾经有一个 shellgoto命令分支到指定的标签,如下所示:。已经goto消失了,但您仍然可以使用 : whatever语法...:现在是一种已解析的注释。

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

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

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


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

更好的选择如下:

echo `# this is a comment` \
foo

答案1

注释在第一个换行符处结束(参见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?)
    :  # do nothing, the file is already compressed
    ;;
  *)
    bzip2 -9 "$1"
    ;;
esac

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

: "${foo:=default value}"

关于 goto 的评论是历史性的。冒号实用程序甚至可以追溯到伯恩外壳,一直到汤普森壳,其中有一个操作说明。冒号意味着标签;冒号是 goto 标签的相当常见的语法(它仍然存在于sed)。

答案2

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

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

"${CMD[@]}"

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

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

关于保留命令和参数的注意事项

${CMD[@]}扩展数组的元素,而不保留每个元素中的字符,否则这些字符将由 shell 解释,例如空格或通配标点符号。一旦扩展,Bash 就会以通常的方式解析所有找到的标记(参见$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

答案3

不要这样做$(: comment)。这不是一个注释 - 这是一个子 shell - 对于大多数 shell 来说是另一个全新的 shell 进程。你的目标是少做一点w/你的输入,而不是更多,这就是这样做的——即使它毫无意义。

你可以做...

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 正在进行替换。它$-每次都会替换特殊 shell 参数的值两次。无论如何,它是一个短字符串,但它是总是设置 - 以及内部替换 - 被解释为从外部剥离的模式 -当我使用扩展形式时,扩展为括号之间的内容-

这里:

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

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

看?所以它只是扩大了两倍。一旦 shell 发现参数已设置,可选扩展字段中的所有内容都会被丢弃,几乎,并且它会扩展为其整个值,该值会从自身中删除,因此什么也没有。在大多数 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

相关内容