说我有文件foo.txt
"The" "quick brown" "fox" "jumps over" "the" "lazy dog."
我想将这些“字段”从文件读入数组。但是,如果字段有空格
,则我的尝试失败$ read -a bar < foo.txt
$ echo ${bar[0]}
"The"
$ echo ${bar[1]}
"quick
我看到答案建议更改IFS
,但这是一行,所以看起来没有帮助。
答案 0 :(得分:2)
这是一个能完成这项工作的功能。对于大型字符串来说可能会很慢,但是可以正常工作,没有像任意代码执行或路径名扩展这样的警告:
#!/bin/bash
parse_quoted_items() {
# Return array is parse_quoted_items_ary
local line=$1
parse_quoted_items_ary=() parse_quoted_items_error=
while [[ $line ]]; do
if [[ $line =~ ^[[:space:]]*\"([^\"]*)\"([[:space:]]+.+|)[[:space:]]*$ ]]; then
parse_quoted_items_ary+=( "${BASH_REMATCH[1]}" )
line=${BASH_REMATCH[2]}
else
parse_quoted_items_error=$line
return 1
fi
done
}
然后你可以用作
IFS= read -r line < foo.txt
if parse_quoted_items "$line"; do
declare -p parse_quoted_items_ary
else
printf >&2 "There was an error parsing the string at %s\n" "$parse quoted_items_error"
exit 1
fi
这不是一个令人满意的答案,但我怀疑有任何(安全)方法没有明确解析字符串。
答案 1 :(得分:1)
IFS
无济于事。这有效:
eval bah=(`cat foo.txt`)
测试:
for i in "${bah[@]}"; do echo $i; done
答案 2 :(得分:1)
使用Perl:
IFS=$'\n' a=( $(perl -ne '@a = split (/("[^"]*")/); for (my $i=1; $i<@a; $i+=2) { print "$a[$i]\n" }' foo.txt) )
注意:这将比纯粹的bash解决方案慢,因为它必须启动Perl解释器。
<强>更新
对于Bash 4+:避免全局设置IFS
:
readarray -t a < <(perl -ne '@a = split (/("[^"]*")/); for (my $i=1; $i<@a; $i+=2) { print "$a[$i]\n" }' foo.txt)
答案 3 :(得分:1)
此解决方案类似于HåkonHægland的:
它还使用Bash的process substitution和readarray
/mapfile
,但Perl部分有点短。
readarray -t words < <(cat fox.txt | perl -i -pe 's/(?<=") (?=")/\n/g')
或只是
readarray -t words < <( perl -pe 's/(?<=") (?=")/\n/g' fox.txt )
使用Perl替换处理该行,使用lookbehind和lookahead来检测"
之后的空格,然后是另一个"
。这些空格将替换为换行符,以允许readarray
将每行读入数组words
。然后将此多行输出传递到readarray
,-t
将在将它们添加到数组之前去除尾随换行符。
请注意,在测试时我很难将perl
的输出直接传递给readarray
,它似乎永远不会读取数组中的一行,因为它是空的。正如@gniourf_gniourf指出的那样,事实上右手程序是在子shell中“绑定”在子shell中创建的任何变量的情况下启动的。
相关资源:
有趣。
答案 4 :(得分:0)
$ . <(sed 's/^/set /' foo.txt)
$ echo $1
The
$ echo $2
quick brown