有一些问题没有很好的答案,关于如何在Bash脚本中按照给定的分隔符拆分字符串。
我的问题是,我有一个用空格分隔的字符串文件,其中可能有引号,例如:
foo bar "foo bar baz" baz
我希望将其拆分为4个值
foo
, bar
, foo bar baz
和baz
。如何通过保留引号将这些输入拆分为Bash数组?bash
shell不支持多字符IFS
分隔符,但由于我们处理的是文件,因此可以使用GNU Awk
并利用其支持FPAT的功能来定义如何处理每个单词。FS
时,gawk
将字段定义为记录中每个字段分隔符之间出现的部分。换句话说,FS
定义了字段不是什么,而不是字段是什么。但是,有时您确实想要根据它们的内容定义字段,而不是根据它们不是什么定义字段。FPAT
的时候,对于您需要处理的以空格分隔的字符串和双引号内的字符串,我们定义一个模式如下,这意味着不是空格(或)包含在双引号中但不是双引号的任何内容。FPAT = "([^[:space:]]+)|("[^"]+")"
但是如果要将其作为字符串写入 Awk
中,则需要对上面的双引号进行转义。
awk 'BEGIN{FPAT = "([^[:space:]]+)|(\"[^\"]+\")"}{for(i=1;i<=NF;i++) print $i}' myFile
foo
bar
"foo bar baz"
baz
从这里开始,要将所有内容存储在 bash
上下文中,您只需要使用进程替换和 mapfile
命令。
mapfile -t newArray < <(awk 'BEGIN{FPAT = "([^[:space:]]+)|(\"[^\"]+\")"}{for(i=1;i<=NF;i++) print $i}' myFile)
然后您可以将数组打印为
declare -p newArray
for item in "${newArray[@]}"; do
printf '%s\n' "$item"
done
如果只有一个带双引号的项目,您可以使用这个sed命令
sed 's/ /\n/g;h;s/[^"]*"\([^"]*\).*/"\1/;s/\n/ /g;x;G;s/\([^"]*\)"\([^"]*\)\("[^"]*\)\n\(".*\)/\1\4\3/' infile
awk -F'"' -vOFS='"' '{for (i=1;i<=NF;i++)if((i%2)==1){gsub(" ","\n",$i)}}1' infile