在这个例子中,IFS是如何工作的?

时间:2012-10-17 11:18:46

标签: bash ifs

我正在阅读有关bash internal variables的内容,并遇到了这个IFS示例:

output_args_one_per_line()
{
  for arg
  do
    echo "[$arg]"
  done #  ^    ^   Embed within brackets, for your viewing pleasure.
}

CASE1

IFS=" "
var=" a  b c   "

output_args_one_per_line $var
#OUTPUT
# [a]
# [b]
# [c]

CASE2

IFS=:
var=":a::b:c:::"               # Same pattern as above
CASE2   
                        # but substituting ":" for " "  ...
output_args_one_per_line $var
# []
# [a]
# []
# [b]
# [c]
# []
# []

现在,根据我的理解,IFS的值是否为默认值\t\n而不是前导空格和尾随空格。因此,对于case1 bash,将var视为a b c,因此输出。

对于case2,根据我bash,var|a||b|c|||视为|space。我用

检查了一下
Noob@Noob:~/tmp$ IFS=$':' FOO=$":a::b:c:::"; echo $FOO $'x'
 a  b c   x

所以,我对案例2的预期输出是

# []
# [a]
# []
# []
# [b]
# [c]
# []
# []
# []

那么,有人可以在内部向我解释bash在案例2中如何处理var以及我在理解的地方出错了。

4 个答案:

答案 0 :(得分:3)

您的声明(已编辑为使用':'代替'|'):

  

对于case2,根据我bash将var视为:a :: b:c ::: treat:as space here。

是假的。 IFS会导致bash:视为单词分隔符,而不是空格。不要因为空格是默认字分隔符而混淆两者。

答案 1 :(得分:2)

:是分隔符。 a:b分为ab,两者之间没有任何内容。在您预期的行为中,您将如何编码以下内容?

[a]
[]
[b]

唯一奇怪的是最后没有三个空字符串。这可能是因为

  

由于没有值的参数的扩展而产生的不带引号的隐式空参数将被删除。

答案 2 :(得分:2)

案例2 上,您":a::b:c:::"IFS=: 所以你正在做的是分裂每个符合:

的字符串

所以,从字符串的开头到第一个:,你有":
这是没有,因此[]

从第一个:到下一个:您有:a:
这是a,因此[a]

从那里到下一个:你有::
这是没有,因此[]

从那里到下一个:你有:b:
这是b,因此[b]

从那里到下一个:你有:c:
这是c,因此[c]

从那里到下一个:你有::
这是没有,因此[]

从那里到下一个:你有::"
这是没有,因此[]

所以你得到了那个结果..


正如@Mark Reed在评论中提到的,你可以使用printf
bash -x一起得到:

$ bash -x
$ IFS=':'; var=':a::b:c:::'; printf "[%s]\n" $var
[12]+ IFS=:
[12]+ var=:a::b:c:::
[12]+ printf '[%s]\n' '' a '' b c '' ''     # notice this
[]
[a]
[]
[b]
[c]
[]
[]

答案 3 :(得分:1)

原因很简单:

IFS=" "
var=" a  b c   "

output_args_one_per_line $var

这意味着使用此参数调用output_args_one_per_line

output_args_one_per_line  a  b c   

在解析命令行时,BASH将删除额外的空格,因此实际调用将使用

output_args_one_per_line a b c

即。多个空格合并为一个,a之前的空格将成为命令和第一个参数之间的空格。

这意味着在应用 IFS之前,空格将消失。这也意味着你不能写

IFS=:
output_args_one_per_line:$var

命令后必须有空格,而不是单词分隔符。

您可以使用set -x运行脚本以查看跟踪输出(即BASH如何扩展行)。

在第二种情况下,单词分隔符不是空格字符,因此命令和第一个参数之间必要的空格不与参数合并,行变为

output_args_one_per_line :a::b:c:::

唯一奇怪的是输出应该是c之后的三个空参数,但这可能是因为删除了空尾随参数(就像BASH在参数之后删除空格一样)。这是另一个奇怪的输出:

IFS=:
var=":a::b:c::: "   # Blank after C
> output_args_one_per_line $var
[]
[a]
[]
[b]
[c]
[]
[]
[ ]

因此,如果var在最后一个冒号之后确实包含任何内容,那么我们会得到缺少的参数。