Necesita mover la última línea del archivo a la segunda línea del mismo archivo

8

Tengo un archivo 'prueba' en Linux con los siguientes datos.

aaaaaa
bbbbbb
cccccc
dddddd
eeeeee

Necesito cortar la última línea de este archivo y ponerlo en la segunda posición. Debe verse a continuación.

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
Vivek William
fuente

Respuestas:

9

Este problema podría ser más fácil de hacer ed, ya que es básicamente un editor de texto programable, en lugar de un procesador de flujo. Utilizando ed, no tiene que guardar todas las líneas del archivo en una matriz, por ejemplo, ya que ya lo está haciendo por usted.

# Create test file
~> printf "%s\n" aaaaaa bbbbbb cccccc dddddd eeeeee >test.txt
~> cat test.txt
aaaaaa
bbbbbb
cccccc
dddddd
eeeeee

# Use ed to open the file, move the last line after the first, save, and quit
~> printf "%s\n" '$m1' wq | ed test.txt
35
35
~> cat test.txt
aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
Godlygeek
fuente
5

Mantener método de búfer:

sed '$x;1!H;1p;$!d;x;s/\n//
' <<\IN
aaaaaa
bbbbbb
cccccc
dddddd
eeeeee
IN

... eso Henvejecerá cada línea que !no sea la primera, y la primera que se ptraza. En la $última línea, xcambia los espacios de espera y de patrón antes de que haga lo Hanterior, que agrega las líneas guardadas a la última línea, y luego delige de la salida todas las líneas que !no son las $últimas.

En la $última línea, xcambia de nuevo los espacios, s///sustituye el primer \ncarácter de línea de hilo, que se encarga del agregado adicional en la línea 2, y luego imprime automáticamente el lote.

SALIDA:

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd

sin usar el búfer Hold:

cat <<\IN >infile
aaaaaa
bbbbbb
cccccc
dddddd
eeeeee
IN

... solo para guardar su ejemplo en un archivo real ...

sed '1p;$!d;r infile' <infile | sed '3d;$d'

Que redirige <infilea los primeros seds' stdin, que sólo pRints la primera línea antes de deleting de salida de todas las líneas que son !no la $última. La última línea es autoprinted, pero también es la única línea en la que se ejecuta la orden final - que es a read a cabo la totalidad infile de nuevo a stdout. Todo eso pasa por la |tubería al segundo, sedque luego solo tiene que delegir de su salida sus líneas de entrada tercera y final para completar la reorganización.

SALIDA:

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
mikeserv
fuente
genial, +1. No recuerdo que alguna vez hayas publicado awksoluciones, ¿eres un gran sedadmirador o quizás escribiste sed? ;-)
iruvar
@ 1_CR - No sé cómo usarlo awk- nunca lo he intentado. tal vez algún día ...
mikeserv
2

Un enfoque ingenuo usando awk:

~$ awk '{a[NR]=$0}END{print a[1];print a[NR];for(i=2;i<NR;i++){print a[i]}}' f
aaaaaa
eeeeee
bbbbbb
cccccc
dddddd

Usted almacena cada línea en la amatriz, luego imprime la matriz en el orden que desee (primera línea, última ( NR) y del 2 al penúltimo.

Usando una combinación de cabeza / cola y sed:

~$ head -1 f;tail -1 f;sed '1d;$d' f
aaaaaa
eeeeee
bbbbbb
cccccc
dddddd

Imprima la primera línea, la última, y ​​con sed elimine la primera y la última.


Solo con sed, solo he podido encontrar este comando. Estoy seguro de que hay mejores formas:

~$ sed '${p;x;s/^\n//;p};2,${H;d}' f
aaaaaa
eeeeee
bbbbbb
cccccc
dddddd

Si es la primera línea, imprímala (por defecto).
Desde la segunda línea, colóquelo en el búfer de retención ( H) y elimine el espacio del patrón ( d). Y si es la última línea, imprímala ( p), luego obtenga el búfer de retención ( x), elimine la línea vacía ( s/^\n//) e imprímala ( p).

fredtantini
fuente
Mi primer instinto sería usar el método cabeza / cola. Una alternativa a la sedparte sería algo así head -n -1 f | tail -n +2.
Sparhawk
@Sparhawk la -1sintaxis para headno es portátil.
mikeserv
1

Con perl:

perl -e 'my @lines = <>; print for @lines[0, $#lines, 1..$#lines-1]' file

Con awk:

$ awk '
    {lines[NR]=$0}
    END{
        print lines[1], lines[NR];
        for (i=2; i<NR; i++) {print lines[i]}
    }
' OFS=$'\n' file

SALIDA

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
Gilles Quenot
fuente