删除特定模式之前、另一个模式之后的所有单词

删除特定模式之前、另一个模式之后的所有单词

我有一个包含很多行的文件。每行以一个模式开始gi_[0-9],紧接着是一个制表符,之后是一个单词列表,所有单词都用分号分隔。我只想保留最后 8 个单词(7 个部分,因为最后一个部分有 2 个单词)。

这是一个例子输入文件:

gi_1\tDog;Pink;Blue;Beige;Yellow;Orange;Red;Green irish

gi_2\tPork;Black;White;Beige;Brown;Cyan;Purple;Red pepper

相应的输出应该:

gi_1\tPink;Blue;Beige;Yellow;Orange;Red;Green irish

gi_2\tBlack;White;Beige;Brown;Cyan;Purple;Red pepper

笔记:我没有找到插入制表符的方法,所以我写了 \t 代替,但是我的文件中有制表标记。

答案1

短的sed方法:

sed 's/^\(.*\t\)[^;]*;/\1/' file

输出:

gi_1    Pink;Blue;Beige;Yellow;Orange;Red;Green irish
gi_2    Black;White;Beige;Brown;Cyan;Purple;Red pepper

  • \(.*\t\)- 捕获第一部分所需的部分

答案2

awk

awk -F '\t' -v OFS='\t' 'sub("^[^;]*;", "", $2)' file.txt
  • sub("^[^;]*;", "", $2)将子字符串替换为;从制表符分隔的 ( -F '\t') 第二个字段开始到第一个的子字符串为 null。sub()是否更换到位

  • -v OFS='\t'将输出字段分隔符设置为制表符

  • 第一个字段(以及其他所有字段)保持原样


为了完整起见,请确保第一个字段gi_后跟一个数字:

awk -F '\t' -v OFS='\t' '$1 ~ /^gi_[[:digit:]]$/ {sub("^[^;]*;", "", $2); print}' file.txt

例子:

% cat file.txt 
gi_1    Dog;Pink;Blue;Beige;Yellow;Orange;Red;Green irish
gi_2    Pork;Black;White;Beige;Brown;Cyan;Purple;Red pepper

% awk -F '\t' -v OFS='\t' 'sub("^[^;]*;", "", $2)' file.txt
gi_1    Pink;Blue;Beige;Yellow;Orange;Red;Green irish
gi_2    Black;White;Beige;Brown;Cyan;Purple;Red pepper

% awk -F '\t' -v OFS='\t' '$1 ~ /^gi_[[:digit:]]$/ {sub("^[^;]*;", "", $2); print}' file.txt
gi_1    Pink;Blue;Beige;Yellow;Orange;Red;Green irish
gi_2    Black;White;Beige;Brown;Cyan;Purple;Red pepper

答案3

使用带有 Perl 风格的 grep 的通用解决方案:

$ a="gi_1 \t Dog;Pink;Blue;Beige;Yellow;Orange;Red;Green irish"
[s@SS data]$ echo $a | grep -P -o "((^gi_. \\\t )|(?<=[; ])(?:.(?!(([; ].+)){8}))+$)" | sed ':a;N;$!ba;s/\n/ /g'
gi_1 \t  Pink;Blue;Beige;Yellow;Orange;Red;Green irish

请注意,这适用于任意数量的单词。

非捕获组和负向先行排除不遵循重复序列 [; 的任何字符。 ] 后跟任意字符。

开头的正向前瞻摆脱了前导的 [; \t] 字符

sed 部分去掉了中间的新行。

答案4

使用 GNU sed,我们可以通过在 do-until 循环结构中查找 6 个分号来完成此操作。

sed -e '
   :loop
      s/\t[^;]*;/\t/
      s/;/&/6
   Tloop
' yourfile

相关内容