
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 sed
que 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 \1
una "referencia inversa" al primer grupo de captura. Usar \1
en 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 sed
comando requiere GNU sed
como estándar sed
, no se pueden insertar nuevas líneas \n
así.
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 awk
para 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 awk
código cuenta el número de veces que se ha visto cada personaje. Lo hace incrementando el valor en la matriz count
correspondiente 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 sed
comando): s/<pattern to search>/<replacement>/
, que ejecutará lo siguiente:
- Para cada línea, búsquela
<pattern>
y sustitúyala por<replacement>
. - La
g
bandera significahazlogramoglobalmente, porque de forma predeterminadased
reemplaza 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 -E
opció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 -e
opciones no son necesarias aquí, a menos que estés concatenando varios sed
comandos: 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: lines
se leen y grep
se 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 .>
join
comb
Bag
key
values
sort
reverse
say