给定 string foo
,我想将它的每个字段存储\n
到 array 的元素中bar
。我想使用read
命令或与旧版本的 bash 兼容的任何其他命令(但readarray
不是)来执行此操作。
我尝试了这个命令:
IFS=$'\n' read -d '' -r -a bar <<< "$foo"
但它只返回错误代码 1。
有什么命令可以用来完成我想要的事情吗?我知道我可以迭代地执行此操作,但显然仅使用一个命令执行此操作是首选。
答案1
read
返回 1,因为在字符串中看不到分隔符。但是,该数组已填充:
$ echo "$BASH_VERSION"
3.2.57(1)-release
$ foo=$'one\ntwo\nthree\nfour'
$ IFS=$'\n' read -d '' -r -a bar <<<"$foo"
$ echo $?
1
$ declare -p bar
declare -a bar='([0]="one" [1]="two" [2]="three" [3]="four")'
使用非空分隔符会产生非零结果:
$ unset bar
$ IFS=$'\n' read -d "\034" -r -a bar <<<"${foo}\034"
$ echo $?
0
$ declare -p bar
declare -a bar='([0]="one" [1]="two" [2]="three" [3]="four")'
八进制 34 是 ASCII“文件分隔符”字符,并且是不太可能出现在您的数据中。
答案2
@glenn jackman 的第一个解决方案的稍微简短的变体:给定
foo=$'one\ntwo\nthree\nfour'
,我们让 Bash 来做全部工作:
set -o noglob # See special Note, below.
IFS=$'\n' bar=($foo)
set +o noglob # See special Note, below.
括号告诉 Bash 我们正在初始化一个数组,其元素就是括号内的内容。就这样,完成了。
编辑添加 笔记:
*
如果输入行可能包含像or 这样的通配元字符?
(man 7 glob
具有完整列表),那么我们必须防止文件名扩展;例如,通过暂时禁用noglob
.感谢您抓住这一点,戈登·戴维森!
确认有效:
echo ${#bar[@]}
4
, 和
echo "[0]:'${bar[0]}' ... [3]:'${bar[3]}'"
[0]:'one' ... [3]:'four'
echo "$BASH_VERSION"
4.1.2(2)-release