如何明确故意分词?

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阅读TFine 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 &lt;&lt;&lt; "$OPTIONS"吗?使用mapfile,您需要将选项放在不同的行中。 虽然read -ra 与禁用 shellcheck 相比可能看起来有点笨拙,但当我有一个带有参数的命令时,它是“必需的”,其中一些参数应该被拆分,而另一些则不需要。例如,我可能想要拆分 OPTIONS,而不是 OUTFILE。此答案涵盖所有情况。 wiki 链接指向 SC2046,而不是 SC2086。 @Cnly 已修复。当您有足够的声誉时,您可以提出对答案的编辑,只要它尊重其原始意图。感谢您发现此错误。 SC2046 的链接是正确的,但实际上提到 SC2086 是错误的。【参考方案3】:

在您展示的任何情况下,没有理由不引用扩展。使用引号。

是否有更明确的关于故意分词的约定,可能避免这个 shellcheck 警告?

约定是使用mapfileread -a 执行分词。

如果您真的想使用分词,那么约定是添加注释,解释您的代码想要依赖分词的原因,然后您还可以添加警告:

# I use word splitting here, because...
# shellcheck disable=SC2046

要禁用 shellcheck 警告,请参阅 shellcheck/wiki/ignore。

注意:在脚本中使用小写变量。按照惯例,大写变量用于导出变量,如PATHPWDUIDCOLUMNSLINES等。

【讨论】:

以上是关于如何明确故意分词?的主要内容,如果未能解决你的问题,请参考以下文章

带你走进中文分词

结巴中文分词原理分析2

什么是搜索引擎分词技术?

垂直细分领域的分词搜索

数学之美笔记第4章 谈谈中文分词

百度中文分词如何分词