![设置变量以扩展为显式空字符串?](https://linux22.com/image/105939/%E8%AE%BE%E7%BD%AE%E5%8F%98%E9%87%8F%E4%BB%A5%E6%89%A9%E5%B1%95%E4%B8%BA%E6%98%BE%E5%BC%8F%E7%A9%BA%E5%AD%97%E7%AC%A6%E4%B8%B2%EF%BC%9F.png)
我有一个 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”过程:
- 获取变量的值,它是一个字符串。
- 在空格处分割字符串(更一般地说,在变量值中存在的字符处
IFS
)。这会产生一个字符串列表(如果原始字符串只包含空格,则可能为空)。 - 对于列表中的每个元素,如果它至少包含一个通配符
*?\[
并且该元素是与至少一个文件匹配的模式,则该元素将被替换为匹配列表。
可以$DOMAIN_SUFFIX
扩展到空字符串列表,但不能扩展到包含空字符串的列表。通配符匹配步骤不能生成空元素,因为文件名永远不是空字符串。拆分步骤无法生成默认值为 的空元素IFS
,因为分隔符是一系列空格,并且至少需要一个非空格字符来中断一系列空格。如果更改为包含非空白字符,则拆分步骤可能会生成空元素IFS
,但这需要更改脚本才能进行修改IFS
,并且没有理由这样做。
您需要更改脚本并使其使用简单的变量扩展,而不是使用 Expand+split+glob 运算符:在变量扩展两边加上双引号。
此外,如果 的值为空,则${DOMAIN_SUFFIX:=.example.com}
扩展为。所以你永远不会得到一个空字符串。要保留空值并仅在未设置时使用,请将更改为。.example.com
DOMAIN_SUFFIX
.example.com
DOMAIN_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.com
DOMAIN_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=''
。