【问题标题】:Word splitting in Bash with IFS set to a non-whitespace characterIFS 设置为非空白字符的 Bash 中的分词
【发布时间】:2017-08-27 01:20:55
【问题描述】:

我正在经历 Bash tutorial,特别是分词的主题。

这个名为“args”的脚本有助于演示分词示例:

#!/usr/bin/env bash
printf "%d args:" $#
printf " <%s>" "$@"
echo

一个例子:

$ ./args hello world, here is "a string of text!"
5 args: <hello> <world,> <here> <is> <a string of text!>

到目前为止一切顺利。我明白这是怎么回事。

但是,当我将 IFS 替换为非空白字符时,例如 :,如果我直接将字符串作为参数传递,则脚本不会执行分词。

$ ./args one:two:three
1 args: <one:two:three>

但是,如果我 (1) 将字符串分配给变量,然后 (2) 通过参数扩展将字符串传递给脚本,则脚本对同一字符串执行分词。

$ IFS=:
$ variable="one:two:three"
$ ./args $variable
3 args: <one> <two> <three>

为什么?具体来说,为什么当 IFS 未设置且分隔符为空白字符时,将字符串作为参数传递会进行分词,而当 IFS 设置为非空白字符时则不会?

当我使用read 而不是这个脚本时,同一个字符串也会按预期进行分词。

$ IFS=:
$ read a b c
one:two:three
$ echo $a $b $c
one two three

【问题讨论】:

    标签: bash shell syntax ifs variable-expansion


    【解决方案1】:

    你可以阅读更多关于分词here的内容。

    shell 扫描参数扩展、命令替换的结果, 以及不会出现在双引号内进行分词的算术扩展。

    当您将裸字符串 one:two:three 作为参数传递且 IFS 设置为 : 时,Bash 不会进行分词,因为裸字符串 不是 参数扩展、命令替换之一,或算术扩展上下文。

    但是,当将相同的字符串分配给变量并且将变量不带引号传递给脚本时,确实会发生分词,因为这是参数扩展的情况。

    同样的事情也适用于这些(命令替换):

    $ ./args $(echo one:two:three)
    3 args: <one> <two> <three>
    
    $ ./args "$(echo one:two:three)"
    1 args: <one:two:three>
    

    documented 一样,read 命令确实会在读取的每一行上进行分词,除非 IFS 已设置为空字符串。


    【讨论】:

    • 干得好,你搞定了:)
    • 我知道参数扩展之后会进行分词,按照gnu.org中详述的shell扩展顺序规则。此外,在您发给我的第一个链接中,最后一行显示“注意,如果不发生扩展,则不执行拆分”。知道了。那么,当我执行 ./args hello world, here is "a string of text!" 时,为什么在这个脚本中完全触发了 is 分词?我没有显式地在那里进行参数扩展,但是进行了分词,这意味着触发了扩展。
    • 我唯一看到的是 IFS 设置为默认空白字符的裸字符串会触发分词,但 IFS 设置为非空白字符的裸字符串不会,除非它是通过参数扩展、命令替换或类似扩展显式调用。我的猜测是,这与 printf 内置函数有关,而且我对 that 的工作原理缺乏了解。当您说“正如记录的那样,read 命令确实在读取的每一行上进行分词,除非 IFS 已设置为空字符串。似乎 printf 做的事情不同。
    • 正则参数被处理为由空格分隔的标记列表,因此您的 printf 中没有 IFS。
    • 完美,谢谢!最后一条评论是回答我预期问题的缺失信息。
    猜你喜欢
    • 2018-02-09
    • 1970-01-01
    • 2014-02-14
    • 2017-06-22
    • 2015-08-28
    • 2012-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多