我有 120 个文件 (genomes.faa),每个文件之间都有标题
>GENOME1_00001 HYPOTHETICAL PROTEIN A
NQFTIAQSQVGLEDALLDL
>GENOME1_00002 HYPOTHETICAL PROTEIN B
NQFTIAQSQVGLEDALLDL
>GENOME1_00003 HYPOTHETICAL PROTEIN C
NQFTIAQSQVGLEDALLDL
etc.
我试图删除名称后面的“_0000X”并将其替换为“|”
>GENOME1|HYPOTHETICAL PROTEIN A
NQFTIAQSQVGLEDALLDL
>GENOME1|HYPOTHETICAL PROTEIN B
NQFTIAQSQVGLEDALLDL
>GENOME1|HYPOTHETICAL PROTEIN C
NQFTIAQSQVGLEDALLDL
etc.
我尝试这样做:
for file in *.faa
do
sed -r 's/_.*$/|/g' $file > $file.1
done
这不会在之后保留“假设蛋白质 A”,从而导致
>ERR1156171|
MMRQSVQTVLP
代替
>ERR1156171|HYPOTHETICAL PROTEIN A
MMRQSVQTVLP
任何帮助表示赞赏!
答案1
我认为你已经非常接近工作指挥了。这对我来说对你给出的几个例子很有用:
sed -E 's/_[0-9]+ /|/' "$file" > "$file.1"
- 我将匹配表达式从 更改
_.*
为_[0-9]+
将匹配限制为仅下划线、数字和空格字符。 - 我删除了
$
因为它匹配行的末尾,而不是第一个单词的末尾。 - 我将替换命令的结尾从 更改
/g
为 ,/
因为您的示例在每一行中只有一个位置需要编辑,而不是多个位置。 - 另外,不要使用
-E
扩展-r
正则表达式,因为前者与其他版本的 sed 更兼容;并引用变量扩展,以防任何文件名包含空格或特殊字符。
答案2
使用这个 Perl 单行命令:
perl -pe 's{^(>\S+?)(_\d+)?\s+(.*)}{$1|$3}' "$file" > "$file.1"
Perl 单行代码使用以下命令行标志:
-e
:告诉 Perl 查找内联代码,而不是在文件中。
-p
:一次循环输入一行,$_
默认将其分配给。print $_
在每次循环迭代后添加。
(...)
:捕获组,后面可以称为$1
、$2
等。
\S+?
:一个或多个非空白字符,非贪婪。
(_\d+)?
:可选的匹配组,由下划线后跟 1 个或多个数字组成。
\s+
: 1 个或多个空白字符。
(.*)
:任意字符,重复 0 次或多次。
也可以看看:
perldoc perlrun
:如何执行Perl解释器:命令行开关
perldoc perlre
:Perl 正则表达式(regexes)
perldoc perlre
:Perl 正则表达式(regexes):量词;字符类和其他特殊转义;断言;捕获组
perldoc perlrequick
:Perl正则表达式快速入门
答案3
这是一个简单的 Perl 单行代码,它将找到_
以 a 开头的行中出现的第一个>
,然后是一个或多个非空白字符 ( \S
),并删除其后的所有非空白字符_
以及其后的所有空白字符:
$ perl -pe 's/^(>\S+)_\S+\s*/$1|/' file
>GENOME1|HYPOTHETICAL PROTEIN A
NQFTIAQSQVGLEDALLDL
>GENOME1|HYPOTHETICAL PROTEIN B
NQFTIAQSQVGLEDALLDL
>GENOME1|HYPOTHETICAL PROTEIN C
NQFTIAQSQVGLEDALLDL
sed
您也可以使用 GNU 做同样的基本事情:
$ sed -E 's/^(>\S+)_\S+\s*/\1|/' file
>GENOME1|HYPOTHETICAL PROTEIN A
NQFTIAQSQVGLEDALLDL
>GENOME1|HYPOTHETICAL PROTEIN B
NQFTIAQSQVGLEDALLDL
>GENOME1|HYPOTHETICAL PROTEIN C
NQFTIAQSQVGLEDALLDL
并与任何sed
:
$ sed 's/^\(>[^[:blank:]]*\)_[^[:blank:]]*[[:blank:]]*/\1\|/' file
>GENOME1|HYPOTHETICAL PROTEIN A
NQFTIAQSQVGLEDALLDL
>GENOME1|HYPOTHETICAL PROTEIN B
NQFTIAQSQVGLEDALLDL
>GENOME1|HYPOTHETICAL PROTEIN C
NQFTIAQSQVGLEDALLDL
答案4
我不知道为什么当你特别要求 bash 时每个人都给出其他语言的代码。
为此,使用 bash 的内置变量扩展工具,它比为每个文件名调用 sed 等外部程序要快得多。对于少数名称而言,这并不重要,但它可能会增加大量文件。
代码
#!/bin/bash
for file in "GENOME1_00001 HYPOTHETICAL PROTEIN A" "GENOME1_00002 HYPOTHETICAL PROTEIN B" "GENOME1_00003 HYPOTHETICAL PROTEIN C"
do
echo -n $file
new_name="${file%_*}|HYPOTHETICAL PROTEIN ${file##*EIN }"
echo " -> ${new_name}"
done
不调用外部工具,产生输出
GENOME1_00001 HYPOTHETICAL PROTEIN A -> GENOME1|HYPOTHETICAL PROTEIN A
GENOME1_00002 HYPOTHETICAL PROTEIN B -> GENOME1|HYPOTHETICAL PROTEIN B
GENOME1_00003 HYPOTHETICAL PROTEIN C -> GENOME1|HYPOTHETICAL PROTEIN C
正如你所要求的。
正如评论中所解释的,我假设行开头的“>”是某种提示,并且只有这些行要被转换。恕我直言,修改代码以适应 Sotto Voce 的反对意见是相当简单的,但话又说回来,也许事实并非如此。按照 Sotto Voce 的要求,这是一个处理所有线路的版本。注意我已将输入数据转换为此处文档,并且像以前一样,为了提高效率,没有调用外部工具。
#!/bin/bash
while read line
do
if [ "${line%%GENOME1_*}" = ">" ]; then
line="${line%_*}|HYPOTHETICAL PROTEIN ${line##*EIN }"
fi
echo "${line}"
done << etc
>GENOME1_00001 HYPOTHETICAL PROTEIN A
NQFTIAQSQVGLEDALLDL
>GENOME1_00002 HYPOTHETICAL PROTEIN B
NQFTIAQSQVGLEDALLDL
>GENOME1_00003 HYPOTHETICAL PROTEIN C
NQFTIAQSQVGLEDALLDL
etc
这是输出:
>GENOME1|HYPOTHETICAL PROTEIN A
NQFTIAQSQVGLEDALLDL
>GENOME1|HYPOTHETICAL PROTEIN B
NQFTIAQSQVGLEDALLDL
>GENOME1|HYPOTHETICAL PROTEIN C
NQFTIAQSQVGLEDALLDL