我有一个如下格式的文件
cat test.txt
id1,PPLLTOMaaaaaaaaaaaJACK
id2,PPLRTOMbbbbbbbbbbbJACK
id3,PPLRTOMcccccccccccJACK
我正在尝试识别并打印 TOM
和 JACK
之间的字符串,包括这两个字符串,同时保持第一列 FS=,
期望的输出:
id1,TOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACK
id3,TOMcccccccccccJACK
到目前为止,我已经尝试过 gsub
:
awk -F"," 'gsub(/.*TOM|JACK.*/,"",$2) && !_[$0]++' test.txt > out.txt
并有以下输出
id1 aaaaaaaaaaa
id2 bbbbbbbbbbb
id3 ccccccccccc
如您所见,我越来越接近了,但无法在我的输出中包含 TOM
和 JACK
模式。另外,我还丢失了原始的 FS
。我做错了什么?
我们将不胜感激。
最佳答案
您正在更改一个字段 ($2
),这会导致 awk 使用 OFS
的值作为字段分隔符来重建记录,因此在本例中将逗号更改为空格。
切勿将 _
用作变量名 - 使用没有意义的名称比使用具有错误含义的名称稍微好一点,只需选择一个有意义的名称,在这种情况下是看到了
,但不知道您在这种情况下使用它时要尝试做什么。
gsub()
和 sub()
不支持捕获组,因此您需要使用 match()
+substr ()
:
$ awk 'BEGIN{FS=OFS=","} match($2,/TOM.*JACK/){$2=substr($2,RSTART,RLENGTH)} 1' file
id1,TOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACK
id3,TOMcccccccccccJACK
或者使用 GNU awk 作为 match()
$ gawk 'BEGIN{FS=OFS=","} match($2,/TOM.*JACK/,a){$2=a[0]} 1' file
id1,TOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACK
id3,TOMcccccccccccJACK
或者对于gensub()
:
$ gawk 'BEGIN{FS=OFS=","} {$2=gensub(/.*(TOM.*JACK).*/,"\\1","",$2)} 1' file
id1,TOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACK
id3,TOMcccccccccccJACK
match()
和 gensub()
解决方案之间的主要区别在于,如果 TOM 在线上出现两次,它们将如何表现:
$ cat file
id1,PPLLfooTOMbarTOMaaaaaaaaaaaJACK
id2,PPLRTOMbbbbbbbbbbbJACKfooJACKbar
id3,PPLRfooTOMbarTOMcccccccccccJACKfooJACKbar
$
$ awk 'BEGIN{FS=OFS=","} match($2,/TOM.*JACK/,a){$2=a[0]} 1' file
id1,TOMbarTOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACKfooJACK
id3,TOMbarTOMcccccccccccJACKfooJACK
$
$ awk 'BEGIN{FS=OFS=","} {$2=gensub(/.*(TOM.*JACK).*/,"\\1","",$2)} 1' file
id1,TOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACKfooJACK
id3,TOMcccccccccccJACKfooJACK
只是为了展示一种在第一个而不是最后一个 JACK 处停止的方法:
$ awk 'BEGIN{FS=OFS=","} match($2,/TOM.*JACK/,a){$2=gensub(/(JACK).*/,"\\1","",a[0])} 1' file
id1,TOMbarTOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACK
id3,TOMbarTOMcccccccccccJACK
关于bash - 在保留格式的同时提取两个模式(包括)之间的字符串,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30041955/