AWK:如果这个是正则表达式,有没有办法将OFS设置为FS?

时间:2016-09-05 07:52:09

标签: regex awk

在awk中,字段(或记录)分隔符FS(或RS)可以设置为正则表达式。 它非常适合获取任何单个字段,但是一旦设置了这些字段,字段分隔符就会“消失”。

echo "a|b-c|d" | awk 'BEGIN{FS="[|-]"} {$3="z"}1'
a b z d 

在这种情况下,输出字段分隔符OFS默认设置为空格。

不幸的是,这种语句OFS=FS="[|-]"无效,因为它将OFS设置为一个字符串。

据我所知,如果有多个选择,awk选择输出字段分隔符可能会变得棘手,但是如果没有新字段,则可以保留当前的字段。

那么,是否有一种简单的方法可以将OFS设置为与FS完全相同的正则表达式,这样我就可以了?

echo "a|b-c|d" | awk '... {$3="z"}1'
a|b-z|d

或者,有没有办法捕获数组中的所有分隔符?例如?

同样的问题也适用于记录分隔符RS(及其关联的ORS

3 个答案:

答案 0 :(得分:5)

正如您已经提到的,无法根据每个案例中使用的OFS动态设置FS。如果正则表达式位于RS而不是FS,则可以使用RT(事实上,我只看到anubhava的答案就是这样,很好!)。

但是,如果你有GNU awk还有另外一种方法:如column replacement with awk, with retaining the format (Ed Morton's answer)所示,你可以使用split(),特别是第四个参数。为什么?因为它在每个切片之间存储分隔符:

gawk 'BEGIN{FS="[|-]"}                     # set FS
     {split($0, a, FS, seps)               # split based on FS and ...
                                           # ...  store pieces in the array seps()
      a[3]="z"                             # change the 3rd field
      for (i=1;i<=NF;i++)                  # print the data back
           printf "%s%s", a[i], seps[i]    # keeping the separators
      print ""                             # print a new line
     }'

作为单行:

$ gawk 'BEGIN{FS="[|-]"} {split($0, a, FS, seps); a[3]="z"; for (i=1;i<=NF;i++) printf "%s%s", a[i], seps[i]; print ""}' <<< "a|b-c|d"
a|b-z|d
  

split(string,array [,fieldsep [,seps]])

     

将字符串分成由fieldsep分隔的片段,并将片段存储在数组中,将分隔符字符串存储在seps数组中。第一部分存储在数组1中,第二部分存储在数组2中,依此类推。第三个参数fieldsep的字符串值是描述拆分字符串的位置的正则表达式(就像FS可以是描述拆分输入记录的位置的正则表达式一样)。如果省略fieldsep,则使用FS的值。 split()返回创建的元素数。 seps是一个gawk扩展,seps [i]是array [i]和array [i + 1] 之间的分隔符字符串。如果fieldsep是单个空格,则任何前导空格都进入seps [0],任何尾随空格进入seps [n],其中n是split()的返回值(即数组中元素的数量)。 / p>

答案 1 :(得分:3)

如果您使用awk(其中N是字段编号)更改任何字段值,则

OFS会使用$N=<whatever>重写每条记录。

由于您在FS中使用了多个分隔符,因此无法使用OFS=FS

如果您有gnu awk,那么您可以使用基于RSRT的解决方案:

s="a|b-c|d"
awk -v RS='[-|]' 'NR==3{$0="z"} {printf "%s%s", $0, RT}' <<< "$s"

a|b-z|d

或者,您可以使用sed

s="a|b-c|d"
sed -E 's/^(([^|-]+[|-]){2})[^|-]+/\1z/' <<< "$s"

a|b-z|d

答案 2 :(得分:0)

由于您显然不需要处理字段,因此只需处理$ 0其他方式,例如下面的sub

$ echo "a|b-c|d" | awk 'BEGIN{FS="[|-]"} {sub(/c/,"z")}1'
a|b-z|d