设置变量以扩展为显式空字符串?

设置变量以扩展为显式空字符串?

我有一个 shell 脚本 ( example) 如下(简化):

#!/bin/sh
./somecommand -s ${DOMAIN_SUFFIX:=.example.com}

如果我运行它./example,它会正确运行./somecommand -s .example.com

如果我运行它DOMAIN_SUFFIX=.stackexchange.com ./example,它会正确运行./somecommand -s .stackexchange.com

问题:如何设置DOMAIN_SUFFIX使其作为显式空字符串传递(在脚本内)?

那就是:我需要它来运行./somecommand -s ''

我已经尝试过了DOMAIN_SUFFIX='' ./example,但是运行./somecommand -s失败了。

答案1

请注意,在 shell 执行完所有扩展并以空字段结束后,除非引用它,否则它会被删除。由于您没有引用该变量,因此如果它解析为空“”,则应将其从“somecommands”参数列表中删除。不仅如此,如果 DOMAIN_SUFFIX 碰巧有空格或通配符,那么您可能会对“somecommand”感到惊讶。

此外, ${DOMAIN_SUFFIX:=.example.com} 是基于您显示的结果的拼写错误:DOMAIN_SUFFIX='' ./example因为空 DOMAIN_SUFFIX 将替换它的默认值,然后将其放置在 somecommand 的参数列表中。因此它永远不会看到“空”。${DOMAIN=.example.com}将解释您得到的结果。

答案2

使用:

“${DOMAIN_SUFFIX=.example.com}”

${参数=默认}, ${参数:=默认}

如果未设置参数,则将其设置为默认值。

两种形式几乎相同。仅当 $parameter 已声明且为 null 时, : 才会产生影响。

http://www.tldp.org/LDP/abs/html/parameter-substitution.html

请注意,您还需要引号""来防止插值后丢弃空值(刚刚注意到您的代码缺少它们,谢谢@Gilles!)。

另请注意,=(或:=) 还会将默认值分配给 DOMAIN_SUFFIX (如果未设置),因此如果您只需要获取该值,您可能需要使用-它。

答案3

TL、博士:为什么我的 shell 脚本会因为空格或其他特殊字符而卡住?。哎呀,这更长了……好吧,真正的 TL,DR:始终在变量和命令替换周围加上双引号。另外,请参阅此答案的结尾,了解您的脚本的第二个问题。

您的脚本不可能将变量扩展扩展为空字符串。不带引号的变量扩展经历“expand+split+glob”过程:

  1. 获取变量的值,它是一个字符串。
  2. 在空格处分割字符串(更一般地说,在变量值中存在的字符处IFS)。这会产生一个字符串列表(如果原始字符串只包含空格,则可能为空)。
  3. 对于列表中的每个元素,如果它至少包含一个通配符*?\[并且该元素是与至少一个文件匹配的模式,则该元素将被替换为匹配列表。

可以$DOMAIN_SUFFIX扩展到空字符串列表,但不能扩展到包含空字符串的列表。通配符匹配步骤不能生成空元素,因为文件名永远不是空字符串。拆分步骤无法生成默认值为 的空元素IFS,因为分隔符是一系列空格,并且至少需要一个非空格字符来中断一系列空格。如果更改为包含非空白字符,则拆分步骤可能会生成空元素IFS,但这需要更改脚本才能进行修改IFS,并且没有理由这样做。

您需要更改脚本并使其使用简单的变量扩展,而不是使用 Expand+split+glob 运算符:在变量扩展两边加上双引号。

此外,如果 的值为空,则${DOMAIN_SUFFIX:=.example.com}扩展为。所以你永远不会得到一个空字符串。要保留空值并仅在未设置时使用,请将更改为。.example.comDOMAIN_SUFFIX.example.comDOMAIN_SUFFIX:==

#!/bin/sh
./somecommand -s "${DOMAIN_SUFFIX=.example.com}"

答案4

bash我认为这是您正在寻找的手册的一部分(POSIX 有类似的措辞具有相同的效果):

当不执行子字符串扩展时,使用下面记录的形式(例如,:-bash测试未设置或为空的参数。省略冒号会导致仅测试未设置的参数。

未设置的变量和具有空值的变量之间的区别在于,未设置的变量甚至不存在。

所以,

#!/bin/bash

bash -c 'echo "$#"; printf "%s\n" "$@"' -- "${DOMAIN_SUFFIX=.example.com}"

如果未设置,则设置为该值,但如果为 null(空字符串),则不会DOMAIN_SUFFIX设置。.example.comDOMAIN_SUFFIX

这里使用的命令将简单地生成一个新bash进程,该进程将打印传入的命令行参数的数量,后跟所有位置参数,每行一个:

bash-4.4$ bash script
1
.example.com
bash-4.4$ DOMAIN_SUFFIX=.hello.world bash script
1
.hello.world
bash-4.4$ DOMAIN_SUFFIX= bash script
1

bash-4.4$

在最后一个示例中,DOMAIN_SUFFIX=与 相同DOMAIN_SUFFIX=''

相关内容