Bash:将行读入数组*而不触及IFS

时间:2014-03-19 21:28:57

标签: arrays bash

我正在尝试将子shell中的输出行读入数组,并且我不愿意设置IFS,因为它是全局的。我不希望脚本的一部分影响以下部分,因为这是不好的做法,我拒绝这样做。在命令不是一个选项后恢复IFS,因为在编辑脚本后将reversion保持在正确的位置太麻烦了。我如何向bash解释我希望每个数组元素都包含整行,而不必设置任何会破坏未来命令的全局变量?

这是一个显示IFS不必要的粘性的例子:

lines=($(egrep "^-o"  speccmds.cmd))
echo "${#lines[@]} lines without IFS"

IFS=$'\r\n' lines=($(egrep "^-o" speccmds.cmd))
echo "${#lines[@]} lines with IFS"

lines=($(egrep "^-o"  speccmds.cmd))
echo "${#lines[@]} lines without IFS?"

输出结果为:

42 lines without IFS
6 lines with IFS
6 lines without IFS?

2 个答案:

答案 0 :(得分:11)

这个问题可能是基于误解。

IFS=foo read 不会在读取操作本身之外更改IFS。

因此,这会产生副作用,应该避免:

IFS=
declare -a array
while read -r; do
  array+=( "$REPLY" )
done < <(your-subshell-here)

...但这完全没有副作用:

declare -a array
while IFS= read -r; do
  array+=( "$REPLY" )
done < <(your-subshell-here)

使用bash 4.0或更新版本时,还可以选择readarraymapfile(同一操作的同义词):

mapfile -t array < <(your-subshell-here)

在后面添加到答案中的示例中,您的代码如下:

lines=($(egrep "^-o"  speccmds.cmd))

更好的方法是:

mapfile -t lines < <(egrep "^-o"  speccmds.cmd)

答案 1 :(得分:6)

您是要尝试将输出的存储在数组中,还是

  1. mapfile -t arrayname < <(your subshell)
    

    这根本不使用IFS。

  2. (your subshell) | while IFS=: read -ra words; do ...
    

    表单var=value command args...var变量放入command的环境中,不会影响当前shell的环境。