Cambiar el orden de las líneas en un archivo

Cambiar el orden de las líneas en un archivo

Estoy intentando cambiar el orden de las líneas en un patrón específico. Trabajar con un archivo con muchas líneas (ej. 99 líneas). Por cada tres líneas, me gustaría que la segunda línea fuera la tercera y la tercera la segunda.

EJEMPLO.

1- Entrada:

gi_1234
My cat is blue.
I have a cat.
gi_5678
My dog is orange.
I also have a dog.
...

2- Salida:

gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.
...

Respuesta1

$ seq 9 | sed -n 'p;n;h;n;G;p'
1
3
2
4
6
5
7
9
8

Es decir, pimprima la línea actual, obtenga la next, hla anterior, obtenga la next, Get la línea retenida (añádala al espacio del patrón) e pimprima ese espacio del patrón de 2 líneas con la tercera y la segunda línea intercambiadas.

Respuesta2

Usando awky matemáticas enteras:

awk 'NR%3 == 1 { print } NR%3 == 2 { delay=$0 } NR%3 == 0 { print; print delay; delay=""} END { if(length(delay) != 0 ) { print delay } }' /path/to/input

El operador de módulo realiza la división de enteros y devuelve el resto, por lo que para cada línea devolverá la secuencia 1, 2, 0, 1, 2, 0 [...]. Sabiendo eso, simplemente guardamos la entrada en las líneas donde el módulo es 2 para más adelante, es decir, justo después de imprimir la entrada cuando es cero.

Respuesta3

Usando perly un guión corto:

user@pc:~$ cat input.txt 
gi_1234
My cat is blue.
I have a cat.
gi_5678
My dog is orange.
I also have a dog.

user@pc:~$ perl -ne '$l2=<>; $l3=<>; print $_,$l3,$l2;' input.txt 
gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.

El script procesa todo el archivo, para cada línea (almacenada en $_) obtendrá las dos líneas siguientes ( $l2y $l3) y las imprimirá en el orden solicitado: línea1, línea3, línea2.

Respuesta4

perla

perl -ne 'print if $.%3==1;$var=$_ if $.%3==2;print $_ . $var if $.%3==0' input.txt

La idea aquí es que usemos el operador de módulo %con $.la variable de número de línea, para determinar cuál es cada primera, cuál es cada segunda y cuál es cada tercera línea. Para cada tercera línea el resto es 0, mientras que para cada primera y segunda línea tendrá los números correspondientes.

Prueba:

$ cat input.txt                                                                                                          
gi_1234
My cat is blue.
I have a cat.
gi_5678
My dog is orange.
I also have a dog.

$ perl -ne 'print if $.%3==1;$var=$_ if $.%3==2;print $_ . $var if $.%3==0' input.txt                                    
gi_1234
I have a cat.
My cat is blue.
gi_5678
I also have a dog.
My dog is orange.

Mejora menor

El enfoque de almacenar la segunda línea en una variable tiene un defecto. ¿Qué pasa si la última línea es la "segunda", es decir, para ese número de línea el resto es 2? El código original en mi respuesta y la de DopeGhoti no se imprimirá My dog is orangesi omitimos la última línea. La solución para esto en ambos casos es usar END{}un bloque de código y desarmar la variable temporal después de la impresión. En otras palabras:

$ awk 'NR%3 == 1 { print } NR%3 == 2 { delay=$0 } NR%3 == 0 { print; print delay;delay=""}END{print delay}' input.txt

y

$ perl -ne '$s=$_ if $.%3==2;print $_ . $s and $s="" if $.%3==0 or $.%3==1;END{print $s}' input.txt 

De esta manera, el código funcionará para un número arbitrario de líneas en un archivo, no solo para aquellas divisibles por 3.

Solución adicional para el problema mencionado en los comentarios.

En el caso de awk, si la última línea del archivo produce un resultado de 1 para $. % 3, el código anterior tiene el problema de generar una nueva línea en blanco debido a la impresión incondicional de END{print delay}, ya que printla función mencionada en los comentarios siempre agrega una nueva línea a cualquier variable en la que esté operando. En el caso de perlla versión, este problema no ocurre, ya que la función with -neflags printno agrega la nueva línea.

No obstante, la solución en el caso de awk es hacer condicional, como lo menciona Dope Ghoti en los comentarios, es verificar la longitud de la variable temporal. La versión Perl de la misma solución sería:

$ perl -ne '$s=$_ if $.%3==2;print $_ . $s and $s="" if $.%3==0 or $.%3==1;END{print $s if length $s}' input.txt 

información relacionada