我认为将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 -t或read循环将文件读入数组。
现在我的问题是:什么时候使用IFS=$'\n'?
您对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)
试试看,如果您有问题,请告诉我。
你的第二次尝试几乎有效,但你必须告诉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':
IFS不带空格的an来避免分词带来的意外副作用;不过,在我看来,正确的方法是理解分词,并确保根据需要正确引用来避免它。IFS=$'\n'在 tab 补全脚本中使用过,例如在 bash-completion 中的那个cd:这个脚本摆弄路径并用换行符替换冒号,然后使用那个将它们分开IFS。