我何时在Bash中将IFS设置为换行符?

lea*_*bee 5 arrays bash ifs

我认为将IFS设置为$'\n'可以帮助我将整个文件读入数组,如下所示:

IFS=$'\n' read -r -a array < file
Run Code Online (Sandbox Code Playgroud)

但是,以上命令仅将文件的第一行读入数组的第一元素,而没有其他内容。

即使这样,它也只读取数组的第一行:

string=$'one\ntwo\nthree'
IFS=$'\n' read -r -a array <<< "$string"
Run Code Online (Sandbox Code Playgroud)

我在该站点上碰到过其他文章,这些文章谈论使用mapfile -tread循环将文件读入数组。

现在我的问题是:什么时候使用IFS=$'\n'

Dav*_*ica 6

您对IFS是什么有点困惑。IFS是bash 使用的内部字段分隔符,用于执行分将行拆分为扩展后的单词。默认值为[ \t\n](空格、制表符、换行符)。

通过重新分配IFS=$'\n',您正在删除' \t'并告诉 bash 只拆分newline字符上的单词(您的想法是正确的)。这具有允许some line with spaces在不引用的情况下读入单个数组元素的效果。

您的实施失败的地方在于您的read -r -a array < file. 的-a原因的话在该行被分配到连续的阵列索引。但是,您已经告诉 bash 只在 a newline(这是整行)上中断。由于您只调用 read 一次,因此只填充了一个数组索引。

你可以这样做:

while IFS=$'\n' read -r line; do
    array+=( $line )
done < "$filename"
Run Code Online (Sandbox Code Playgroud)

IFS如果你简单地引用,你可以不改变它"$line"

或者使用IFS=$'\n',你可以做

IFS=$'\n'
array=( $(<filename) )
Run Code Online (Sandbox Code Playgroud)

或者最后,你可以使用IFSand readarray

readarray array <filename
Run Code Online (Sandbox Code Playgroud)

试试看,如果您有问题,请告诉我。

  • 很高兴我们能提供帮助。在这两个答案之间,您现在应该对“IFS”有很好的感觉。可能需要更长的时间才能适应术语*分词*和*扩展*以及bash如何应用它们——这是正常的,随着时间的推移它会沉没。不要忘记 *man bash*,它拥有一切,只是需要一段时间才能弄清楚如何舒适地阅读它。当您可以使用简单的 *man bash* 和 `/searchterm` 找到您需要的内容时,您就可以很好地掌握 shell。祝你脚本编写好运`:)`。 (3认同)

Ben*_* W. 5

你的第二次尝试几乎有效,但你必须告诉read它不应该只读取到换行符(默认行为),而是例如直到空字符串:

$ IFS=$'\n' read -a arr -d '' <<< $'a b c\nd e f\ng h i'
$ declare -p arr
declare -a arr='([0]="a b c" [1]="d e f" [2]="g h i")'
Run Code Online (Sandbox Code Playgroud)

但是正如您所指出的,如果您拥有它,mapfile/readarray是要走的路(需要 Bash 4.0 或更高版本):

$ mapfile -t arr <<< $'a b c\nd e f\ng h i'
$ declare -p arr
declare -a arr='([0]="a b c" [1]="d e f" [2]="g h i")'
Run Code Online (Sandbox Code Playgroud)

-t选项从每个元素中删除换行符。

至于你什么时候想使用IFS=$'\n'

  • 如上所示,如果您想将文件读入数组,每个元素一行,如果您的 Bash 早于 4.0,并且您不想使用循环
  • 有些人提倡使用IFS不带空格的an来避免分词带来的意外副作用;不过,在我看来,正确的方法是理解分词,并确保根据需要正确引用来避免它。
  • 我已经看到IFS=$'\n'在 tab 补全脚本中使用过,例如在 bash-completion 中的那个cd:这个脚本摆弄路径并用换行符替换冒号,然后使用那个将它们分开IFS