bash - awk - bash,如何选择由空格分隔的文件的三个字段,然后用另一个标志分隔的其他字段?

  显示原文与译文双语对照的内容

我的文件格式如下:


aaa bbb ccc ddd eee|fff|ggg|hhh|iii|lll|mmm|nnn|ooo|ppp


aaa1 bbb1 ccc1 ddd1 eee1|fff1|ggg1|hhh1|iii1|lll1|mmm1|nnn1|ooo1|ppp1


aaa2 bbb2 ccc2 ddd2 eee2|fff2|ggg2|hhh2|iii2|lll2|mmm2|nnn2|ooo2|ppp2



正如你所看到的,前三个字段由一个空格分隔,另一个字段由| 符号分隔。 我想选择第一个 3字段,然后选择 8th 和 9th 字段。

我希望有以下输出:


aaa bbb ccc hhh iii


aaa1 bbb1 ccc1 hhh1 iii1


aaa2 bbb2 ccc2 hhh2 iii2



如你所见,我应该在两个分隔符上过滤: 空格和管道。

我怎么能在bash上做什么?

我试过 awk,但不能用两个不同的分隔符来运行它。

时间:

如果你的代码对性能不敏感以至于使awk成为更好的选择,那么下面的代码就会在本机bash中进行解析,并且即使管道分隔的字段也能以这样的方式获得正确的结果除了第一个包含空格:


while IFS='|' read -r -a psep_fields; do # read into pipe-separated fields


 read -r -a space_fields <<<"${psep_fields[0]}" # read 1st field & parse by spaces


 printf '%s %s %s %s %sn' 


"${space_fields[0]}""${space_fields[1]}""${space_fields[2]}" 


"${psep_fields[3]}""${psep_fields[4]}"


done



请参见 https://ideone.com/zCjpDP 上的运行,作为输出返回:


aaa bbb ccc hhh iii


aaa1 bbb1 ccc1 hhh1 iii1


aaa2 bbb2 ccc2 hhh2 iii2



如果输入可以能在管道字符串中的第 4个字段或者空格中有管道,则最好使用 awk 将第5个字段拆分为:


awk 'NF>3{s=$1 OFS $2 OFS $3; $1=$2=$3=""; 


if (split($0, a,"|")> 4) s = s OFS a[4] OFS a[5]; print s}' file




aaa bbb ccc hhh iii


aaa1 bbb1 ccc1 hhh1 iii1


aaa2 bbb2 ccc2 hhh2 iii2



一个稍微不同的方法-


while read a b c d e


do IFS="|" read -a f <<<"$e"


 echo"$a $b $c ${f[3]} ${f[4]}"


done <input.txt


aaa bbb ccc hhh iii


aaa b|b|b ccc hhh"i i i"


aaa1 bbb1 ccc1 hhh1 iii1


aaa1 bbb1 c|c|c|1 hhh1" i i i 1"


aaa2 bbb2 ccc2 hhh2 iii2


aaa2 bbb2 ccc2"h h h 2" iii2



读取字段在通常的$IFS 字符上分割,将所有最后一个批处理分隔为 e 。 这将保留 a - d 中嵌入的所有管道字符。 由于 e 是最后一个变量,行的其余部分存储在那里,即使它有嵌入的空格。

仅在管道中显式地将 e 拆分为名为 f的array 。 这将保留 e 字段中嵌入的任何空格字符。

它和下面的Charles的解决方案并没有什么区别。

这将完全做到你要求的,无论头( 间隔隔开) 部分中的字段包含 | s 或者字段中的字段包含空格。

使用 GNU 第三方 arg 到 match() 和 S/s shorthand:


$ cat tst.awk


match($0,/^((S+s+){3})(.*)/,a) {


 split(a[1],h,/s+/)


 split(a[3],t,/[|]/)


 print h[1], h[2], h[3], t[4], t[5]


}



$ awk -f tst.awk file


aaa bbb ccc hhh iii


aaa1 bbb1 ccc1 hhh1 iii1


aaa2 bbb2 ccc2 hhh2 iii2



和任何 awk:


$ cat tst.awk


match($0,/^([^[:space:]]+[[:space:]]+){3}/) {


 split(substr($0,RSTART,RLENGTH),h,/[[:space:]]+/)


 split(substr($0,RSTART+RLENGTH),t,/[|]/)


 print h[1], h[2], h[3], t[4], t[5]


}



$ awk -f tst.awk file


aaa bbb ccc hhh iii


aaa1 bbb1 ccc1 hhh1 iii1


aaa2 bbb2 ccc2 hhh2 iii2



上面假设你是正确的,它只是由空格分隔的前 3个字段,因这里 {3} 中的。 如果你错了,它实际上是 4 ( 看起来好像是你发布的样本里的),那么显然只是把 {3} 改为 {4} 。 如果你想访问一个 4个空格分隔域,它将只会发生。

...