考虑
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 没有解释这些解决方案为何有效。我希望得到解释。他回复了评论:
曾经有一个 shell
goto
命令分支到指定的标签,如下所示:
。已经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