
Achei este comando interessante:
grep -v '^>' test.fasta | tr -d '\n' | sed -e 's/\(.\)/\1\n/g' | sort | uniq -c | sort -rn
Eu tenho alguma ideia do que isso significa (conta letras de um arquivo de texto), mas minha pergunta é sobre isso:
sed -e 's/\(.\)/\1\n/g'
Eu sei que é composto por três comandos substitutos. Uma é substituir novas linhas ( \n
), por uma que corresponda a qualquer caractere, exceto novas linhas ( \(.\)
), mas estou perdido em /\1\
?
Responder1
O comando
sed -e 's/\(.\)/\1\n/g'
é um único sed
comando de substituição GNU que substitui cada caractere por ele mesmo, seguido por um caractere de nova linha. O efeito disso é dobrar a entrada em uma única coluna de caracteres únicos.
$ echo hello | sed -e 's/\(.\)/\1\n/g'
h
e
l
l
o
O \(.\)
é um "grupo de captura", capturando um único personagem. É \1
uma "referência retroativa" ao primeiro grupo de captura. Usar \1
no texto de substituição inseriria tudo o que foi capturado pelos primeiros parênteses.
Também poderia ser escrito sem tantas barras invertidas como
sed 's/./&\n/g'
onde &
significa simplesmente "tudo o que foi correspondido pela expressão".
O sed
comando requer GNU sed
como padrão, sed
não é possível inserir novas linhas \n
assim.
Para fazer isso de forma mais eficiente com ferramentas padrão, use
fold -w 1
em vez de. Isso é mais eficiente, pois nenhuma correspondência de expressão regular é necessária para cada caractere na entrada.
Usando fold
, seu pipeline pode ser escrito
grep -v '^>' file | tr -d '\n' | fold -w 1 | sort | uniq -c | sort -rn
Alternativamente, usando awk
para se livrar de algumas etapas desse pipeline,
awk '!/^>/ { for (i = 1; i <= length; ++i) count[substr($0,i,1)]++ }
END { for (ch in count) print count[ch], ch }' file |
sort -rn
O awk
código conta o número de vezes que cada personagem foi visto. Isso é feito incrementando o valor na matriz count
correspondente a cada caractere no fluxo de entrada. No final da entrada, um resumo das contagens e dos caracteres contados é exibido.
Responder2
Espero que isso deixe tudo mais claro.
"Eu sei que é composto por três comandos substitutos"
É apenas um comando substituto (se você estiver se referindo ao sed
comando): s/<pattern to search>/<replacement>/
, que executará o seguinte:
- Para cada linha procure
<pattern>
e substitua por<replacement>
. - A
g
bandeira significafaça issoglobalmente, porque por padrãosed
substitui apenas a primeira ocorrência de<pattern>
.
"mas estou perdido em
/\1\
"
Você pode capturar um padrão colocando-o entre parênteses de escape \(<pattern>\)
ou apenas parênteses com a -E
opção (<pattern>)
.
Na <replacement>
seção, esse padrão capturado é referenciado por uma barra invertida e um número, \<number>
. O número refere-se à posição da captura, já que você pode ter vários:
sed -E '/(<first capture>)(<second capture>)/\1\2/'
Portanto, o comando sed -e 's/\(.\)/\1\n/g'
significa:
- Capture cada caractere
\(.\)
e substitua-o por ele mesmo e por uma nova linha\1\n
. - Com
g
, faça isso globalmente, não pare na primeira ocorrência.
Por exemplo:
$ echo foo | sed -E 's/(.)/\1\n/g'
f
o
o
As -e
opções não são necessárias aqui, a menos que você esteja concatenando vários sed
comandos: sed -e '...' -e '...'
, etc.
Você pode encontrar mais informações emReferências anteriores e subexpressões.
Responder3
Usando Raku (anteriormente conhecido como Perl_6)
raku -e 'for lines.grep({ !/ ^ \> / }).join { .say for .comb.Bag.sort(*.values).reverse};'
Entrada de amostra:
>sp|P01308|INS_HUMAN Insulin OS=Homo sapiens OX=9606 GN=INS PE=1 SV=1
MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKTRREAED
LQVGQVELGGGPGAGSLQPLALEGSLQKRGIVEQCCTSICSLYQLENYCN
Saída de amostra:
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
O código que você apresenta pode ser escrito em vários idiomas (não apenas sed
), qualquer um dos quais pode tocar você. Por exemplo, seu código acima foi reescrito em Raku, um membro da família de linguagens Perl.
A maior parte do código Raku deve ser bastante autoexplicativo: lines
são lidos e grep
-ped para a !
ausência de um ângulo 'maior que' no ^
início da linha e -ed. As linhas unidas são -ed (divididas em caracteres individuais), -ged (cada caractere presente se torna a e as ocorrências são contadas/registradas como ), -ed in para colocar o maior número de ocorrências primeiro e depois impressas com .>
join
comb
Bag
key
values
sort
reverse
say