如何明确故意分词?
Posted
技术标签:
【中文标题】如何明确故意分词?【英文标题】:How to be explicit about intentional word splitting? 【发布时间】:2020-10-19 13:51:19 【问题描述】:我在我的脚本上运行 shellcheck 并且经常收到此警告(在这种情况下这是正确的,因为 cd foo bar baz
没有意义):
cd $SOME_DIR || exit 1
^-- SC2046: Quote this to prevent word splitting.
这个警告大多是好的。变量包含多个参数时的一个例外:
gcc $OPTIONS ...
^-- SC2046: Quote this to prevent word splitting.
是否有更明确的关于故意分词的约定,可能避免这个 shellcheck 警告?
【问题讨论】:
@KamilCuk 已更新。不知道本地压制,因为它没有出现在手册页中。很高兴知道:) @GillesQuenot 更新了不同的示例。 @Andreas :至少第一种情况对我来说仍然没有意义,因为分词可能会产生类似cd foo bar baz
的东西,无论如何这是错误的。第二个例子有点不幸,因为与echo
命令结合使用会简单地表达“用输出中的单个空格替换变量中的一系列空格”。更现实的例子是 gcc $OPTIONS foo.cc
,您希望 OPTIONS 字符串在空白处进行拆分,或者您使用 IFS
来拆分其他字符的情况。
在更新后不引用DIR_STRING
也不是一个好主意。关于引用分配:右侧does not undergo word splitting,所以var=$(echo 'foo bar')
将保留空格(但请注意内部引用!),但var=foo bar
仍然需要引号,var='foo bar'
。
@KamilCuk :IMO 你应该让你的评论成为答案,因为它不仅回答了 OP 的问题,而且总体上看起来很有帮助。我想知道是否还有相应的enable=
指令,因为可能只想关闭一小部分代码的警告。
【参考方案1】:
在您的脚本中,# shellcheck disable=...
形式的 cmets 将禁用特定警告。
options="a b c"
# shellcheck disable=2086
foo $options
如果您在本地运行shellcheck
脚本,则可以使用-e
选项而不是向脚本添加指令。
$ cat tmp.sh
#/bin/sh
options="a b c"
foo $options
$ shellcheck tmp.sh
In tmp.sh line 5:
foo $options
^------^ SC2086: Double quote to prevent globbing and word splitting.
Did you mean:
foo "$options"
For more information:
https://www.shellcheck.net/wiki/SC2086 -- Double quote to prevent globbing ...
$ spellcheck -e SC2086 foo.sh
$
【讨论】:
【参考方案2】:当没有分割意图时,只需添加双引号:
cd "$SOME_DIR" || exit 1
执行显式拆分为数组:
read -ra gcc_options <<<"$OPTIONS"
gcc "$gcc_options[@]"
或为下一条语句禁用 shellcheck,表明您已将操作审核为符合意图:
# shellcheck disable=SC2046 # Intended splitting of OPTIONS
gcc $OPTIONS
有时R阅读T他Fine Manual是比在这里询问更好的选择:
Shellcheck 提供指向其 Wiki 的链接,以获取代码检查警告。 SC2046 Quote this to prevent word splitting wiki 条目已经提到在 Bash 中使用 read -a
以及如何针对非 Bash shell 语法的特定情况禁用此代码检查。
【讨论】:
也许我们还应该指出,您的第一种方法需要 bash 或 ksh。由于 OP 也使用了 sh 标签,他可能也对 Bourne/POSIX shell 解决方案感兴趣。 第二个不应该是read -ra gcc_options <<< "$OPTIONS"
吗?使用mapfile
,您需要将选项放在不同的行中。
虽然read -ra
与禁用 shellcheck 相比可能看起来有点笨拙,但当我有一个带有参数的命令时,它是“必需的”,其中一些参数应该被拆分,而另一些则不需要。例如,我可能想要拆分 OPTIONS,而不是 OUTFILE。此答案涵盖所有情况。
wiki 链接指向 SC2046,而不是 SC2086。
@Cnly 已修复。当您有足够的声誉时,您可以提出对答案的编辑,只要它尊重其原始意图。感谢您发现此错误。 SC2046 的链接是正确的,但实际上提到 SC2086 是错误的。【参考方案3】:
在您展示的任何情况下,没有理由不引用扩展。使用引号。
是否有更明确的关于故意分词的约定,可能避免这个 shellcheck 警告?
约定是使用mapfile
或read -a
执行分词。
如果您真的想使用分词,那么约定是添加注释,解释您的代码想要依赖分词的原因,然后您还可以添加警告:
# I use word splitting here, because...
# shellcheck disable=SC2046
要禁用 shellcheck 警告,请参阅 shellcheck/wiki/ignore。
注意:在脚本中使用小写变量。按照惯例,大写变量用于导出变量,如PATH
PWD
UID
COLUMNS
LINES
等。
【讨论】:
以上是关于如何明确故意分词?的主要内容,如果未能解决你的问题,请参考以下文章