我发现这个有趣的命令:
grep -v '^>' test.fasta | tr -d '\n' | sed -e 's/\(.\)/\1\n/g' | sort | uniq -c | sort -rn
我对它的含义有所了解(它计算文本文件中的字母),但我的问题是这样的:
sed -e 's/\(.\)/\1\n/g'
我知道它由三个替代命令组成。一种是替换换行符(\n
),即匹配除换行符(\(.\)
)之外的任何字符,但我迷失了/\1\
?
答案1
命令
sed -e 's/\(.\)/\1\n/g'
是一个 GNUsed
替换命令,它将每个字符替换为自身,后跟换行符。这样做的效果是将输入折叠成单个字符的单列。
$ echo hello | sed -e 's/\(.\)/\1\n/g'
h
e
l
l
o
这\(.\)
是一个“捕获组”,捕获单个字符。这\1
是对第一个捕获组的“反向引用”。\1
在替换文本中使用将插入第一个括号捕获的任何内容。
它也可以写成没有那么多反斜杠,例如
sed 's/./&\n/g'
其中&
仅表示“表达式匹配的任何内容”。
该sed
命令要求 GNUsed
作为标准,sed
不能\n
像这样插入换行符。
要使用标准工具更有效地完成此操作,请使用
fold -w 1
反而。这更有效,因为输入中的每个字符不需要正则表达式匹配。
使用fold
,您的管道可以编写
grep -v '^>' file | tr -d '\n' | fold -w 1 | sort | uniq -c | sort -rn
或者,使用awk
来摆脱该管道的几个步骤,
awk '!/^>/ { for (i = 1; i <= length; ++i) count[substr($0,i,1)]++ }
END { for (ch in count) print count[ch], ch }' file |
sort -rn
该awk
代码计算每个字符出现的次数。它通过递增count
与输入流中的每个字符对应的数组中的值来实现这一点。输入结束时,输出计数和字符计数的摘要。
答案2
我希望这能让事情变得更清楚。
“我知道它是由三个替代命令组成的”
这只是一个替代命令(如果您指的是该sed
命令):,s/<pattern to search>/<replacement>/
它将执行以下命令:
- 对于每一行搜索
<pattern>
并将其替换为<replacement>
。 - 国旗
g
的意思是做吧G全局性的,因为默认情况下sed
仅替换第一次出现的<pattern>
.
“但我迷失了
/\1\
”
\(<pattern>\)
您可以通过使用转义括号或仅使用选项括起来来捕获模式-E
。(<pattern>)
在本<replacement>
节中,捕获的模式由反斜杠和数字 引用\<number>
。该数字指的是捕获的位置,因为您可以有多个:
sed -E '/(<first capture>)(<second capture>)/\1\2/'
所以该命令的sed -e 's/\(.\)/\1\n/g'
意思是:
- 捕获每个字符
\(.\)
并用其自身和新行替换它\1\n
。 - 使用
g
,全局执行,不要在第一次出现时停止。
例如:
$ echo foo | sed -E 's/(.)/\1\n/g'
f
o
o
-e
此处不需要这些选项,除非您要连接多个sed
命令:sed -e '...' -e '...'
等。
您可以在以下位置找到更多信息:反向引用和子表达式。
答案3
使用 Raku(以前称为 Perl_6)
raku -e 'for lines.grep({ !/ ^ \> / }).join { .say for .comb.Bag.sort(*.values).reverse};'
输入示例:
>sp|P01308|INS_HUMAN Insulin OS=Homo sapiens OX=9606 GN=INS PE=1 SV=1
MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKTRREAED
LQVGQVELGGGPGAGSLQPLALEGSLQKRGIVEQCCTSICSLYQLENYCN
示例输出:
L => 20
G => 12
A => 10
E => 8
Q => 7
P => 6
C => 6
V => 6
R => 5
S => 5
Y => 4
F => 3
T => 3
N => 3
M => 2
D => 2
K => 2
I => 2
W => 2
H => 2
您提供的代码可以用多种语言(不仅仅是sed
)编写,其中任何一种都可能引起您的共鸣。例如,上面的代码已用 Raku(Perl 语言家族的成员)重新编写。
大多数 Raku 代码应该是相当不言自明的:lines
读入,并grep
-ped 表示!
缺少^
行首>
“大于”角度,并join
-ed。连接的行是comb
-ed (分成单独的字符),Bag
-ged (每个出现的字符变成 akey
并且出现次数被计数/记录为values
),sort
-ed inreverse
首先放置最高的出现次数,然后用 打印say
。