等于换行符的 IFS 在 bash 中不起作用
IFS equal to newline character is not working in bash
我有一个多行字符串,我想根据 \n
进行拆分,为此我设置了 IFS=$'\n'
但它不起作用,我也尝试过 IFS=
和IFS="
"
但运气不好。
下面是示例代码
IFS=$'\n' read -ra arr <<< "line1\nline2\nline3"
printf "%s\n" "${arr[@]}"
# it only generates array of length 1
我正在使用 Ubuntu
,bash 版本为
GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
<http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
谁能指出显而易见的地方。
来自 bash 手册,bash 内置部分:
read
read [-ers] [-a aname] [-d delim] [-i text] [-n nchars]
[-N nchars] [-p prompt] [-t timeout] [-u fd] [name …]
One line is read from the standard input, or from the file descriptor fd supplied as an argument to the -u option,
行分隔符可以用-d
指定
-d delim
The first character of delim is used to terminate the input line, rather than newline.
注意后面跟一个空参数-d ''
,行分隔符就是nul字符,如果input中没有nul字符,可以用来读取整个input
但是即使使用 -r
模式,读取速度也很慢。
对于更大的输入,更快的解决方案可以是使用分词:
input=$'line1\nline2\nline3'
IFS=$'\n';set -f;arr=($input);set +f;IFS=$' \t\n'
注意 set -f
以避免全局匹配阶段。
您尝试的主要问题是 分词 未使用 herestring 进行预制。来自男人 bash:
Here Strings
A variant of here documents, the format is:
<<<word
... Pathname expansion and word splitting are not performed.
The result is supplied as a single string to the command on its
standard input.
Bash 确实提供了 heredoc(例如 "Here Document" in man bash),word-splitting 将使用默认值 IFS
执行。然而,即便如此,您仍然会读取文字 '\n'
作为数组内容的一部分。不用担心,bash 提供了一种特定的方式,可以通过 readarray
的 -t
选项来避免这种情况(a/k/a mapfile
)。
一个尽可能接近您最初尝试的简短示例是:
readarray -t arr << EOF
line1
line2
line3
EOF
declare -p arr
这会导致您的行按需要保存,例如输出将是:
declare -a arr='([0]="line1" [1]="line2" [2]="line3")'
另一种选择是使用 进程替换 并让 printf
提供拆分,例如
readarray -t arr < <(printf "line1\nline2\nline3\n")
不包含换行符的填充数组的关键是readarray -t
,允许分词发生的关键是避免herestring.
我有一个多行字符串,我想根据 \n
进行拆分,为此我设置了 IFS=$'\n'
但它不起作用,我也尝试过 IFS=
和IFS="
"
但运气不好。
下面是示例代码
IFS=$'\n' read -ra arr <<< "line1\nline2\nline3"
printf "%s\n" "${arr[@]}"
# it only generates array of length 1
我正在使用 Ubuntu
,bash 版本为
GNU bash, version 4.4.19(1)-release (x86_64-pc-linux-gnu)
Copyright (C) 2016 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later
<http://gnu.org/licenses/gpl.html>
This is free software; you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
谁能指出显而易见的地方。
来自 bash 手册,bash 内置部分:
read
read [-ers] [-a aname] [-d delim] [-i text] [-n nchars]
[-N nchars] [-p prompt] [-t timeout] [-u fd] [name …]
One line is read from the standard input, or from the file descriptor fd supplied as an argument to the -u option,
行分隔符可以用-d
-d delim
The first character of delim is used to terminate the input line, rather than newline.
注意后面跟一个空参数-d ''
,行分隔符就是nul字符,如果input中没有nul字符,可以用来读取整个input
但是即使使用 -r
模式,读取速度也很慢。
对于更大的输入,更快的解决方案可以是使用分词:
input=$'line1\nline2\nline3'
IFS=$'\n';set -f;arr=($input);set +f;IFS=$' \t\n'
注意 set -f
以避免全局匹配阶段。
您尝试的主要问题是 分词 未使用 herestring 进行预制。来自男人 bash:
Here Strings A variant of here documents, the format is: <<<word ... Pathname expansion and word splitting are not performed. The result is supplied as a single string to the command on its standard input.
Bash 确实提供了 heredoc(例如 "Here Document" in man bash),word-splitting 将使用默认值 IFS
执行。然而,即便如此,您仍然会读取文字 '\n'
作为数组内容的一部分。不用担心,bash 提供了一种特定的方式,可以通过 readarray
的 -t
选项来避免这种情况(a/k/a mapfile
)。
一个尽可能接近您最初尝试的简短示例是:
readarray -t arr << EOF
line1
line2
line3
EOF
declare -p arr
这会导致您的行按需要保存,例如输出将是:
declare -a arr='([0]="line1" [1]="line2" [2]="line3")'
另一种选择是使用 进程替换 并让 printf
提供拆分,例如
readarray -t arr < <(printf "line1\nline2\nline3\n")
不包含换行符的填充数组的关键是readarray -t
,允许分词发生的关键是避免herestring.