使用 sed/awk 从重复行中删除模式

Use sed/awk to remove pattern from repeating lines

我在文件中有以下模式

TREE(abc/x73/APPLE)   DEST(MYFILE.FILE1A) 
TREE(abc/x74/APPLE)   DEST(MYFILE88.FILE1A) 
TREE(abc/x100/APPLE)  DEST(MYFILE100.FILE1B) 
TREE(abc/x61/APPLE)   DEST(MYFILE1000.FILE1A)

我希望理想的输出是:

TREE(abc/x73/APPLE)   FILE1A
TREE(abc/x74/APPLE)   FILE1A
TREE(abc/x100/APPLE)  FILE1B
TREE(abc/x61/APPLE)   FILE1A

但是,我会接受:

TREE(abc/x73/APPLE)   DEST(FILE1A)
TREE(abc/x74/APPLE)   DEST(FILE1A)
TREE(abc/x100/APPLE)  DEST(FILE1B)
TREE(abc/x61/APPLE)   DEST(FILE1A)

我试过

的变体
sed 's/\(FILE1A\).*//'

但我一直得到与输入相同的结果。对于我哪里出错的任何指示,我将不胜感激。

谢谢。

这是否解决了您的问题?

cat test.txt
TREE(abc/x73/APPLE)   DEST(MYFILE.FILE1A)
TREE(abc/x74/APPLE)   DEST(MYFILE88.FILE1A)
TREE(abc/x100/APPLE)  DEST(MYFILE100.FILE1B)
TREE(abc/x61/APPLE)   DEST(MYFILE1000.FILE1A)

sed -n 's/\(.*)\).*\.\(.*\))/\t/p' test.txt
TREE(abc/x73/APPLE) FILE1A
TREE(abc/x74/APPLE) FILE1A
TREE(abc/x100/APPLE)    FILE1B
TREE(abc/x61/APPLE) FILE1A

解释:

-n 选项 - 不打印所有内容

\(.*)\) 第一个捕获组 - 包括第一个“)”在内的所有内容

\.\(.*\)) 第二个捕获组 - “.”之间的所有内容最后一个“)”

\t/p 打印第一个捕获组,然后是制表符,然后是第二个捕获组

sed 's/MYFILE[[:digit:]]\{0,\}\.//' file.txt

输出

TREE(abc/x73/APPLE)   DEST(FILE1A)
TREE(abc/x74/APPLE)   DEST(FILE1A)
TREE(abc/x100/APPLE)  DEST(FILE1B)
TREE(abc/x61/APPLE)   DEST(FILE1A)

sed 's/DEST.\{1,\}\.//;s/)$//' file.txt

输出

TREE(abc/x73/APPLE)   FILE1A
TREE(abc/x74/APPLE)   FILE1A
TREE(abc/x100/APPLE)  FILE1B
TREE(abc/x61/APPLE)   FILE1A

我将按如下方式利用 GNU AWK 来完成此任务,让 file.txt 内容成为

TREE(abc/x73/APPLE)   DEST(MYFILE.FILE1A) 
TREE(abc/x74/APPLE)   DEST(MYFILE88.FILE1A) 
TREE(abc/x100/APPLE)  DEST(MYFILE100.FILE1B) 
TREE(abc/x61/APPLE)   DEST(MYFILE1000.FILE1A)

然后

awk 'BEGIN{FS="DEST\([[:alpha:][:digit:]]*\.|\)[[:space:]]*$"}{print  }' file.txt

输出

TREE(abc/x73/APPLE)   FILE1A
TREE(abc/x74/APPLE)   FILE1A
TREE(abc/x100/APPLE)  FILE1B
TREE(abc/x61/APPLE)   FILE1A

说明:我将字段分隔符 (FS) 设置为包含两个选项的值(由 | 剪切)

  • DEST( 零个或多个字母数字点 (.)
  • ) 后跟零个或多个空格(您的文件有尾随 空格) 和行尾 ($)

由于 () 以及 . 具有特殊含义,我需要将它们转义以获得文字 ( 和文字 ) 以及文字 . 我需要的。我 print 值第 1 列的内容(即 TREE(...) 和尾随空格)与第 2 列的值 FILE1A 连接,依此类推。

(在 gawk 4.2.1 中测试)

使用awk你可以得到两个结果:

使用gsub()函数的第一个输出:

awk '{gsub(/^[^.]+.|)$/,"",)} 1' file | column -tc2
TREE(abc/x73/APPLE)   FILE1A
TREE(abc/x74/APPLE)   FILE1A
TREE(abc/x100/APPLE)  FILE1B
TREE(abc/x61/APPLE)   FILE1A

sub() 的第二个输出:

awk '{sub(/MYFILE[[:digit:]]*./,"",)} 1' file | column -tc2
TREE(abc/x73/APPLE)   DEST(FILE1A)
TREE(abc/x74/APPLE)   DEST(FILE1A)
TREE(abc/x100/APPLE)  DEST(FILE1B)
TREE(abc/x61/APPLE)   DEST(FILE1A)

并使用 column -tc2 您可以保留(或调整)列之间的间距。

您还可以使用更具体的模式,并使用 negated character class 匹配除左括号和右括号之间的括号之外的任何字符。

  • ( 捕获 组 1
    • \([^()]*\)[[:blank:]][[:blank:]]* 匹配从第一个开始 ( 到结束 ) 和后面的空格或制表符
  • ) 关闭组 1
  • [^()]* 可选择匹配除 ()
  • 之外的任何字符
  • \(匹配第二个左括号
  • [^()]*\. 匹配除 () 之外的任何字符,然后匹配一个点
  • ([^()]*) 捕获 组 2
  • 中除 () 之外的任何字符
  • \) 匹配第二个右括号

查看捕获组的 regex demo

sed -n 's/\(([^()]*)[[:blank:]][[:blank:]]*\)[^()]*([^()]*\.\([^()]*\))//p' test.txt

输出

TREE(abc/x73/APPLE)   FILE1A 
TREE(abc/x74/APPLE)   FILE1A 
TREE(abc/x100/APPLE)  FILE1B 
TREE(abc/x61/APPLE)   FILE1A

如果数据的格式始终与示例数据中的一样,使用 gnu awk,您还可以捕获第二个字段的右括号之前的最后一个字母数字字符,并使用制表符作为输出字段分隔符。

awk -v OFS='\t' '
match(, /([[:alnum:]]+)\)/, a){print , a[1]}
' test.txt

输出

TREE(abc/x73/APPLE)     FILE1A
TREE(abc/x74/APPLE)     FILE1A
TREE(abc/x100/APPLE)    FILE1B
TREE(abc/x61/APPLE)     FILE1A