Bash 在保留格式的同时提取两个模式(包括)之间的字符串
我有一个以下格式的文件Bash 在保留格式的同时提取两个模式(包括)之间的字符串,bash,shell,awk,gsub,Bash,Shell,Awk,Gsub,我有一个以下格式的文件 cat test.txt id1,PPLLTOMaaaaaaaaaaaJACK id2,PPLRTOMbbbbbbbbbbbJACK id3,PPLRTOMcccccccccccJACK 我试图识别并打印TOM和JACK之间的字符串,包括这两个字符串,同时维护第一列FS=, 期望输出: id1,TOMaaaaaaaaaaaJACK id2,TOMbbbbbbbbbbbJACK id3,TOMcccccccccccJACK 到目前为止,我已经尝试了gsub: awk -
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
$ gawk 'BEGIN{FS=OFS=","} {$2=gensub(/.*(TOM.*JACK).*/,"\\1","",$2)} 1' file
id1,TOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACK
id3,TOMcccccccccccJACK
并具有以下输出
id1 aaaaaaaaaaa
id2 bbbbbbbbbbb
id3 ccccccccccc
如您所见,我正在接近,但无法在输出中包含TOM
和JACK
模式。另外,我还丢失了原来的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\).*/\1\2/' <test.txt > out.txt
sed的/^\([^,]*,\).\(TOM.*JACK\)./\1\2/'out.txt
您正在更改一个字段($2
),这会导致awk使用OFS
的值作为字段分隔符来重建记录,因此在本例中,将逗号更改为空格
永远不要将\uuuu
用作变量名-使用没有意义的名称要比使用有错误意义的名称稍微好一点,只需选择一个具有某种含义的名称,在本例中是所见的,但请确定在本上下文中使用该名称时要做什么
gsub()
和sub()
不支持捕获组,因此您需要使用match()
+substr()
:
或者对第三个参数使用GNU awk来match()
或对于gensub()
:
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
$ awk 'BEGIN{FS=OFS=","} match($2,/TOM.*JACK/,a){$2=gensub(/(JACK).*/,"\\1","",a[0])} 1' file
id1,TOMbarTOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACK
id3,TOMbarTOMcccccccccccJACK
只是为了展示一种在第一个而不是最后一个插孔处停车的方法:
$ 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
$ awk 'BEGIN{FS=OFS=","} match($2,/TOM.*JACK/,a){$2=gensub(/(JACK).*/,"\\1","",a[0])} 1' file
id1,TOMbarTOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACK
id3,TOMbarTOMcccccccccccJACK
如果一行中包含TOMabcBOB
,则可能会出现不希望出现的情况。只要TOM和JACK在预期的位置存在,这应该可以工作。什么可能不起作用的示例?像id,fooTOMabcBOB
这样的行,如果它可以存在于输入中,则会被不希望地更改为id,tomabcb
。我也不这样做,但它阻止了我在awk答案中使用类似的解决方案:-)。
sed 's/\(.*,\).*\(TOM.*JACK\).*/\1\2/' <oldfile >newfile
id1,TOMaaaaaaaaaaaJACK
id2,TOMbbbbbbbbbbbJACK
id3,TOMcccccccccccJACK