在GNU Awk 的 4.1.2 Record Splitting with 中,gawk我们可以阅读:
当
RS是单个字符时,RT包含相同的单个字符。但是,whenRS是正则表达式,RT包含与正则表达式匹配的实际输入文本。
这个变量RT在某些情况下非常有用。
同样,我们可以设置一个正则表达式作为字段分隔符。例如,在这里我们允许它是“;” 或“|”:
$ gawk -F';' '{print NF}' <<< "hello;how|are you"
2 # there are 2 fields, since ";" appears once
$ gawk -F'[;|]' '{print NF}' <<< "hello;how|are you"
3 # there are 3 fields, since ";" appears once and "|" also once
Run Code Online (Sandbox Code Playgroud)
但是,如果我们想再次打包数据,我们没有办法知道两个字段之间出现了哪个分隔符。因此,如果在前面的示例中我想遍历字段并使用 再次将它们打印在一起FS,它会在每种情况下打印整个表达式:
$ gawk -F'[;|]' '{for (i=1;i<=NF;i++) printf ("%s%s", $i, FS)}' <<< "hello;how|are you"
hello[;|]how[;|]are you[;|] # a literal "[;|]" shows in the place of FS
Run Code Online (Sandbox Code Playgroud)
有没有办法使用用于拆分每个字段的特定字段分隔符来“重新打包”字段,类似于 RT 允许做的事情?
(问题中给出的例子相当简单,但只是为了说明这一点)
有没有办法使用用于拆分每个字段的特定字段分隔符来“重新打包”字段
使用gnu-awk split()它使用提供的正则表达式为匹配的分隔符提供额外的第四个参数:
s="hello;how|are you"
awk 'split($0, flds, /[;|]/, seps) {for (i=1; i in seps; i++) printf "%s%s", flds[i], seps[i]; print flds[i]}' <<< "$s"
hello;how|are you
Run Code Online (Sandbox Code Playgroud)
一个更易读的版本:
s="hello;how|are you"
awk 'split($0, flds, /[;|]/, seps) {
for (i=1; i in seps; i++)
printf "%s%s", flds[i], seps[i]
print flds[i]
}' <<< "$s"
Run Code Online (Sandbox Code Playgroud)
注意第四个seps参数,split它通过第三个参数 ie 中使用的正则表达式存储匹配文本的数组/[;|]/。
当然,它不像RS,ORS和那样简短RT,可以写成:
awk -v RS='[;|]' '{ORS = RT} 1' <<< "$s"
Run Code Online (Sandbox Code Playgroud)
作为@anubhava提到,GAWK具有split()(并且patsplit()这是FPAT因为split()是FS-看https://www.gnu.org/software/gawk/manual/gawk.html#String-Functions)做你想要什么。如果您想要与 POSIX awk 相同的功能,那么:
$ cat tst.awk
function getFldsSeps(str,flds,fs,seps, nf) {
delete flds
delete seps
str = $0
if ( fs == " " ) {
fs = "[[:space:]]+"
if ( match(str,"^"fs) ) {
seps[0] = substr(str,RSTART,RLENGTH)
str = substr(str,RSTART+RLENGTH)
}
}
while ( match(str,fs) ) {
flds[++nf] = substr(str,1,RSTART-1)
seps[nf] = substr(str,RSTART,RLENGTH)
str = substr(str,RSTART+RLENGTH)
}
if ( str != "" ) {
flds[++nf] = str
}
return nf
}
{
print
nf = getFldsSeps($0,flds,FS,seps)
for (i=0; i<=nf; i++) {
printf "{%d:[%s]<%s>}%s", i, flds[i], seps[i], (i<nf ? "" : ORS)
}
}
Run Code Online (Sandbox Code Playgroud)
请注意上面对字段分隔符的具体处理," "因为这意味着与所有其他字段分隔符值不同的两件事:
例如,在这 3 个输入文件上运行上面的代码:
$ head file{1..3}
==> file1 <==
hello;how|are you
==> file2 <==
hello how are_you
==> file3 <==
hello how are_you
Run Code Online (Sandbox Code Playgroud)
我们会得到以下输出,其中每个字段显示为字段编号,然后是字段值,[...]然后是分隔符<...>,所有内容都在{...}(请注意,seps[0]填充了 FS 所在的 IFF" "并且记录以空格开头):
$ awk -F'[,|]' -f tst.awk file1
hello;how|are you
{0:[]<>}{1:[hello;how]<|>}{2:[are you]<>}
$ awk -f tst.awk file2
hello how are_you
{0:[]<>}{1:[hello]< >}{2:[how]< >}{3:[are_you]<>}
$ awk -f tst.awk file3
hello how are_you
{0:[]< >}{1:[hello]< >}{2:[how]< >}{3:[are_you]<>}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
176 次 |
| 最近记录: |