Explicação de um comando sed

Explicação de um comando sed

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 sedcomando 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. É \1uma "referência retroativa" ao primeiro grupo de captura. Usar \1no 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 sedcomando requer GNU sedcomo padrão, sednão é possível inserir novas linhas \nassim.

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 awkpara 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 awkcódigo conta o número de vezes que cada personagem foi visto. Isso é feito incrementando o valor na matriz countcorrespondente 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 sedcomando): s/<pattern to search>/<replacement>/, que executará o seguinte:

  • Para cada linha procure <pattern>e substitua por <replacement>.
  • A gbandeira significafaça issoglobalmente, porque por padrão sedsubstitui 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 -Eopçã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 -eopções não são necessárias aqui, a menos que você esteja concatenando vários sedcomandos: 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: linessã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 .>joincombBagkeyvaluessortreversesay

https://raku.org

informação relacionada