在保留格式的同时提取两个模式(包括)之间的字符串

Extract string between two patterns (inclusive) while conserving the format

我有一个格式如下的文件

cat test.txt
id1,PPLLTOMaaaaaaaaaaaJACK
id2,PPLRTOMbbbbbbbbbbbJACK
id3,PPLRTOMcccccccccccJACK

我正在尝试识别并打印 TOMJACK 之间的字符串,包括这两个字符串,同时保持第一列 FS=,

期望的输出:

id1,TOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACK
id3,TOMcccccccccccJACK

到目前为止我已经试过了gsub:

awk -F"," 'gsub(/.*TOM|JACK.*/,"",) && !_[[=12=]]++' test.txt > out.txt

并有以下输出

id1 aaaaaaaaaaa
id2 bbbbbbbbbbb
id3 ccccccccccc

如您所见,我越来越接近了,但无法在我的输出中包含 TOMJACK 模式。另外我也失去了原来的 FS。我做错了什么?

任何帮助将不胜感激。

您是要执行以下操作吗?

$ cat test.txt
id1,PPLLTOMaaaaaaaaaaaJACKABCD
id2,PPLRTOMbbbbbbbbbbbJACKDFCC
id3,PPLRTOMcccccccccccJACKSDER

$ cat test.txt | sed -e 's/,.*TOM/,TOM/g' | sed -e 's/JACK.*/JACK/g'
id1,TOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACK
id3,TOMcccccccccccJACK
$

只要 TOM 和 JACK 不重复,这应该可以工作。

使用捕获组来保存你想要保留的行的部分。这是使用 sed

的方法
sed 's/^\([^,]*,\).*\(TOM.*JACK\).*//' <test.txt > out.txt

您正在更改字段 (</code>),这会导致 awk 使用 <code>OFS 的值作为字段分隔符重建记录,因此在本例中将逗号更改为空格。

切勿将 _ 用作变量名 - 使用没有意义的名称仅比使用具有错误含义的名称稍微好一点,只需选择一个有意义的名称,在这种情况下是 seen 但不知道您在这种情况下使用它时要做什么。

gsub()sub() 不支持捕获组,因此您需要使用 match()+substr():

$ awk 'BEGIN{FS=OFS=","} match(,/TOM.*JACK/){=substr(,RSTART,RLENGTH)} 1' file
id1,TOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACK
id3,TOMcccccccccccJACK

或者使用 GNU awk 作为第三个参数 match()

$ gawk 'BEGIN{FS=OFS=","} match(,/TOM.*JACK/,a){=a[0]} 1' file
id1,TOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACK
id3,TOMcccccccccccJACK

gensub():

$ gawk 'BEGIN{FS=OFS=","} {=gensub(/.*(TOM.*JACK).*/,"\1","",)} 1' file
id1,TOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACK
id3,TOMcccccccccccJACK

match()gensub() 解决方案之间的主要区别在于,如果 TOM 在线上出现两次,它们的行为方式:

$ cat file
id1,PPLLfooTOMbarTOMaaaaaaaaaaaJACK
id2,PPLRTOMbbbbbbbbbbbJACKfooJACKbar
id3,PPLRfooTOMbarTOMcccccccccccJACKfooJACKbar
$
$ awk 'BEGIN{FS=OFS=","} match(,/TOM.*JACK/,a){=a[0]} 1' file
id1,TOMbarTOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACKfooJACK
id3,TOMbarTOMcccccccccccJACKfooJACK
$
$ awk 'BEGIN{FS=OFS=","} {=gensub(/.*(TOM.*JACK).*/,"\1","",)} 1' file
id1,TOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACKfooJACK
id3,TOMcccccccccccJACKfooJACK

并且只是为了展示一种在第一个而不是最后一个 JACK 处停止的方法:

$ awk 'BEGIN{FS=OFS=","} match(,/TOM.*JACK/,a){=gensub(/(JACK).*/,"\1","",a[0])} 1' file
id1,TOMbarTOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACK
id3,TOMbarTOMcccccccccccJACK
sed 's/\(.*,\).*\(TOM.*JACK\).*//' <oldfile >newfile

输出:

id1,TOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACK
id3,TOMcccccccccccJACK