我最近才开始使用 Linux,几乎完全不了解 sed 命令。我需要使用 sed 命令编辑一个包含一堆以常见字符“>”开头的长行的文件,并删除此行的其余部分,只保留第一个单词,但不触及任何不以“>”开头的行。
换句话说,我需要将其(仅为演示目的的第一个条目的一部分)转换为:
>YAL001C TFC3 SGDID:S000000001, Chr I from 151006-147594,151166-151097, Genome Release 64-1-1, reverse complement, Verified ORF, "Largest of six subunits of the RNA polymerase III transcription initiation factor complex (TFIIIC); part of the TauB domain of TFIIIC that binds DNA at the BoxB promoter sites of tRNA and similar genes; cooperates with Tfc6p in DNA binding"
MVLTIYPDELVQIVSDKIASNKGKITLNQLWDISGKYFDLSDKKVKQFVLSCVILKKDIE
VYCDGAIP*
变成这样:
>YAL001C
MVLTIYPDELVQIVSDKIASNKGKITLNQLWDISGKYFDLSDKKVKQFVLSCVILKKDIE
VYCDGAIP*
答案1
我在这里提出四个解决方案,两个使用sed
,一个使用awk
,一个使用perl
。首先:
$ sed -r 's/^(>[^ ]+) .*/\1/' inputfile
在您的示例输入上,这将产生输出:
>YAL001C
LTIYPDELVQIVSDKIASNKGKITLNQLWDISGKYFDLSDKKVKQFVLSCVILKKDIE
VYCDGAIP*
代码使用了 sed 的替代命令s
。替代命令的形式为s/old/new/
。在本例中,“旧”部分由以下部分组成:
^
这是 sed 中表示行开头的意思。
(>[^ ]+)
这是指由尖括号和一个或多个非空白字符组成的一组字符。由于这是在括号中,因此我们稍后可以将其称为
\1
。.*
指的是空格后跟任意数量的任意字符。
当替换命令完成后,任何这样的行的全部内容都将被替换为紧随>
其后的非空白字符。
任何不以该组合开头的行都将不加改变地发送到输出。
替代解决方案
在评论中,steeldriver 建议了一种替代方法:
sed '/^>/ s/\s.*//'
在这个解决方案中,替换命令前面有一个修饰符/^>/
,它限制替换命令只能对以 开头的行进行操作>
。知道该行以尖括号开头,那么只需要删除第一个空格以及第一个空格后面的所有内容。这就是命令的作用s/\s.*//
。
所有其他线路均按原样通过。
替代解决方案使用awk
awk '/^>/ {print $1;next} 1' inputfile
该awk
脚本由两个表达式组成:
/^>/ {print $1;next}
awk
支持与 相同的修饰符样式sed
。因此,初始表达式限制此命令仅对以 开头的行进行操作>
。对于这些行,将打印第一个字段。next
指示awk
跳至下一行并重新开始。1
1
是awk
打印整行的神秘简写。此命令仅next
在未执行前一个表达式中的命令的行上执行,这意味着awk
仅当行不以 开头时才会到达此命令>
。
替代解决方案使用perl
steeldriver 还建议:
perl -anle 'print $F[0] if /^>/ || $_'
四个选项含义如下:
-n
告诉perl
隐式循环输入行-a
告诉 perl 启用自动分割,创建@F
数组-l
启用自动行结束处理-e
告诉它运行后面的命令,从而无需 perl 脚本文件。
perl 命令本身相当易读:
print $F[0] if /^>/ || $_
如果行以 开头,则此命令打印第一个字段>
。否则,它将打印整行。