Explicación de un comando sed

Explicación de un comando sed

Encontré este comando interesante:

grep -v '^>' test.fasta | tr -d '\n' | sed -e 's/\(.\)/\1\n/g' | sort | uniq -c | sort -rn

Entiendo un poco lo que significa (cuenta letras de un archivo de texto), pero mi pregunta es sobre esto:

sed -e 's/\(.\)/\1\n/g'

Sé que se compone de tres comandos sustitutos. Una es sustituir nuevas líneas ( \n), una que coincida con cualquier carácter excepto nuevas líneas ( \(.\)), pero estoy perdido en /\1\?

Respuesta1

El comando

sed -e 's/\(.\)/\1\n/g'

es un comando de sustitución único de GNU sedque reemplaza cada carácter por sí mismo, seguido de un carácter de nueva línea. El efecto de esto es plegar la entrada en una sola columna de caracteres individuales.

$ echo hello | sed -e 's/\(.\)/\1\n/g'
h
e
l
l
o

Es \(.\)un "grupo de captura", que captura un solo carácter. Es \1una "referencia inversa" al primer grupo de captura. Usar \1en el texto de reemplazo insertaría lo que fue capturado por el primer paréntesis.

También podría escribirse sin tantas barras invertidas como

sed 's/./&\n/g'

donde &simplemente significa "lo que coincida con la expresión".

El sedcomando requiere GNU sedcomo estándar sed, no se pueden insertar nuevas líneas \nasí.

Para hacerlo de manera más eficiente con herramientas estándar, use

fold -w 1

en cambio. Esto es más eficiente ya que no se necesita una expresión regular para cada carácter de la entrada.

Usando fold, su canalización podría escribirse

grep -v '^>' file | tr -d '\n' | fold -w 1 | sort | uniq -c | sort -rn

Alternativamente, usar awkpara deshacerse de algunos pasos de esa canalización,

awk '!/^>/ { for (i = 1; i <= length; ++i) count[substr($0,i,1)]++ }
    END { for (ch in count) print count[ch], ch }' file |
sort -rn

El awkcódigo cuenta el número de veces que se ha visto cada personaje. Lo hace incrementando el valor en la matriz countcorrespondiente a cada carácter en el flujo de entrada. Al final de la entrada, se genera un resumen de los recuentos y los caracteres contados.

Respuesta2

Espero que esto lo aclare.

"Sé que se compone de tres comandos sustitutos"

Es solo un comando sustituto (si te refieres al sedcomando): s/<pattern to search>/<replacement>/, que ejecutará lo siguiente:

  • Para cada línea, búsquela <pattern>y sustitúyala por <replacement>.
  • La gbandera significahazlogramoglobalmente, porque de forma predeterminada sedreemplaza solo la primera aparición de <pattern>.

"pero estoy perdido en /\1\"

Puede capturar un patrón rodeándolo con paréntesis de escape \(<pattern>\), o simplemente entre paréntesis con la -Eopción (<pattern>).

En la <replacement>sección, se hace referencia a este patrón capturado mediante una barra invertida y un número, \<number>. El número hace referencia a la posición de la captura, ya que puedes tener varios:

sed -E '/(<first capture>)(<second capture>)/\1\2/'

Entonces el comando sed -e 's/\(.\)/\1\n/g'significa:

  • Capture cada carácter \(.\)y reemplácelo por sí mismo y por una nueva línea \1\n.
  • Con g, hazlo globalmente, no te detengas en la primera aparición.

Por ejemplo:

$ echo foo | sed -E 's/(.)/\1\n/g'
f
o
o


Las -eopciones no son necesarias aquí, a menos que estés concatenando varios sedcomandos: sed -e '...' -e '...', etc.


Puedes encontrar más información enReferencias anteriores y subexpresiones.

Respuesta3

Usando Raku (anteriormente conocido como Perl_6)

raku -e 'for lines.grep({ !/ ^ \> / }).join { .say for .comb.Bag.sort(*.values).reverse};'

Entrada de muestra:

>sp|P01308|INS_HUMAN Insulin OS=Homo sapiens OX=9606 GN=INS PE=1 SV=1
MALWMRLLPLLALLALWGPDPAAAFVNQHLCGSHLVEALYLVCGERGFFYTPKTRREAED
LQVGQVELGGGPGAGSLQPLALEGSLQKRGIVEQCCTSICSLYQLENYCN

Salida de muestra:

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

El código que presenta se puede escribir en varios idiomas (no solo sed), cualquiera de los cuales puede tocarle la fibra sensible. Como ejemplo, el código anterior se ha reescrito en Raku, un miembro de la familia de lenguajes Perl.

La mayor parte del código Raku debería explicarse por sí mismo: linesse leen y grepse escriben con -ped por la !ausencia de un ángulo "mayor que" ^al inicio de la línea , y con -ed. Las líneas unidas están -ed (divididas en caracteres individuales), -ged (cada carácter presente se convierte en a y las ocurrencias se cuentan/registran como ), -ed para colocar primero el mayor número de ocurrencias y luego se imprimen con .>joincombBagkeyvaluessortreversesay

https://raku.org

información relacionada