在awk中,字段(或记录)分隔符FS(或RS)可以设置为正则表达式.它非常适合获取任何单个字段,但是一旦设置了这些字段,字段分隔符就会"消失".
echo "a|b-c|d" | awk 'BEGIN{FS="[|-]"} {$3="z"}1'
a b z d
Run Code Online (Sandbox Code Playgroud)
在这种情况下,输出字段分隔符OFS默认设置为空格.
不幸的是,这种语句OFS=FS="[|-]"不起作用,因为它设置OFS为一个字符串.
我知道如果有多个选择,awk选择输出字段分隔符可能会变得棘手,但是如果没有新字段,则可以保留当前的字段.
那么,有没有一种简单的方法可以设置OFS为完全相同的正则表达式FS,这样我得到了这个?
echo "a|b-c|d" | awk '... {$3="z"}1'
a|b-z|d
Run Code Online (Sandbox Code Playgroud)
或者,有没有办法捕获数组中的所有分隔符?
同样的问题也适用于记录分隔符RS(及其相关ORS)
正如您已经提到的,没有办法OFS根据FS每个案例使用的动态设置.如果正则表达式RS代替FS,你可以使用RT(事实上,我只是看到anubhava的回答是这样的,很好!).
但是,如果你有GNU awk,还有另一种方法:如用awk替换列,保留格式(Ed Morton的答案),你可以使用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
}'
Run Code Online (Sandbox Code Playgroud)
作为单线:
$ 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
Run Code Online (Sandbox Code Playgroud)
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()的返回值(即数组中元素的数量).