当前位置:  开发笔记 > 编程语言 > 正文

如何在bash中控制IFS分词

如何解决《如何在bash中控制IFS分词》经验,为你挑选了1个好方法。

我试图弄清楚IFS如何影响bash中的单词拆分.行为依赖于上下文,其方式似乎与单词拆分的直觉不相符.

一般的想法似乎很简单.引用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分词的上下文的推荐的惯用方法是什么?



1> chepner..:

认识到这一点很重要,为什么下面的失败:

$ IFS=, echo_n foo,bar,baz
Num args: 1, Args: foo,bar,baz

预命令分配IFS仅适用于内部 echo_n ; foo,bar,baz不会拆分,,因为在此命令行(或缺少)上的任何分词都会 echo_n运行之前发生.

(IFS=,; for i in foo,bar,baz ; do echo_n $i; done)

导致单次迭代,因为IFS它仅用于分割扩展的结果(以及通过read,见下文),而不是文字字符串.shell在第一次解析命令行时完成的分词实际上是硬编码的,只能在空格上分割.


目前还不完全清楚你想要完成什么,但一个好的经验法则是,如果你设定IFS全局的价值,你做错了(或者至少是次优的).只有两种情况我可以回想起有用的修改IFS:

    IFS=, read -r a b c将包含逗号的行拆分为多个(此处为3个).改变IFS是本地的read; 无论串读取读取保存完好,只有拆分内部通过read.

    foo=$(IFS=.; echo "${foo[*]}")将数组的元素连接到单个字符串中,并使用a .作为分隔符.请注意,这是全局更改IFS,但仅限于在命令替换完成后消失的全局范围.

for循环示例相关,只要您想要迭代硬编码列表以外的其他内容(包括数组的扩展),您可能希望使用while循环read而不是for循环,根据Bash FAQ 001.

把你的for循环放在这里,例如:

(IFS=,; for i in $(echo foo,bar,baz) ; do echo_n $i; done)

我会先将它拆分成一个数组,然后迭代for:

data="foo,bar,baz"
IFS=, read -r -a items <<< "$data"
for i in "${data[@]}"; do
    echo_n "$i"
done

推荐阅读
Life一切安好
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有