我正在尝试弄清楚IFS如何影响bash中的单词拆分。这种行为是上下文相关的,不符合单词拆分的直觉。
一般的想法似乎足够简单。从bash手册引用:
“shell将IFS的每个字符视为分隔符,并在这些字符上将其他扩展的结果拆分为单词。...请注意,如果没有发生扩展,则不执行拆分。”
例如,可以将IFS变量设置为“,”,并使用逗号分隔的参数列表调用shell函数来轻松验证此功能。
正如预期的那样,这将导致echo_n有三个明显不同的参数。
一般的想法似乎足够简单。从bash手册引用:
“shell将IFS的每个字符视为分隔符,并在这些字符上将其他扩展的结果拆分为单词。...请注意,如果没有发生扩展,则不执行拆分。”
例如,可以将IFS变量设置为“,”,并使用逗号分隔的参数列表调用shell函数来轻松验证此功能。
echo_n () {
echo Num args: $#, Args: "$@"
}
( IFS=','
args=foo,bar,baz
echo_n $args
)
正如预期的那样,这将导致echo_n有三个明显不同的参数。
Num args: 3, Args: foo bar baz
直接使用逗号分隔的列表调用 echo_n 失败,因为不会触发任何扩展。
IFS=, echo_n foo,bar,baz
导致结果
Num args: 1, Args: foo,bar,baz
到这里为止,事情看起来相当扭曲,但我可以理解它们。当我们开始在其中添加for循环时,情况变得更加复杂。
(IFS=,; for i in foo,bar,baz ; do echo_n $i; done)
导致
Num args: 3, Args: foo bar baz
这样做就违背了for循环的目的。
现在,我可以通过几种bash技巧来强制触发IFS单词拆分。例如:
(IFS=,; for i in ${NO_VAR:-foo,bar,baz} ; do echo_n $i; done)
导致
Num args: 1, Args: foo
Num args: 1, Args: bar
Num args: 1, Args: baz
这个技巧的关键在于使用默认值来评估一个未定义的变量NO_VAR。
另一个类似的技巧,依赖于命令替换:
(IFS=,; for i in $(echo foo,bar,baz) ; do echo_n $i; done)
那么问题来了:控制IFS单词分割执行的推荐、惯用方法是什么?