Precisa mover a última linha do arquivo para a segunda linha do mesmo arquivo

8

Eu tenho um arquivo 'teste' no linux com os dados abaixo.

aaaaaa
bbbbbb
cccccc
dddddd
eeeeee

Preciso cortar a última linha deste arquivo e colocá-lo na segunda posição. Deve parecer como abaixo.

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
Vivek William
fonte

Respostas:

9

Na verdade, esse problema pode ser mais fácil ed, pois é basicamente um editor de texto com script, em vez de um processador de fluxo. Usando ed, você não precisa salvar todas as linhas do arquivo em uma matriz, por exemplo, pois já está fazendo isso por você.

# 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
fonte
5

Método de retenção de buffer:

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

... que Henvelhecerá todas as linhas que !não são a primeira e a primeira que pé Na $última linha, ele xaltera os espaços de espera e de padrão antes da Hantiga - que obtém as linhas salvas anexadas à última linha - e delimina da saída todas as linhas que !não são as $últimas.

Na $última linha, ele xmuda de espaço novamente, s///substituindo o primeiro \ncaractere de linha de linha - que cuida do extra adicionado na linha 2 - e imprime automaticamente o lote.

RESULTADO:

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd

sem usar o buffer de retenção:

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

... apenas para salvar seu exemplo em um arquivo real ...

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

Que redireciona <infilepara os primeiros seds' stdin, que só prints a primeira linha antes deleting de saída de todas as linhas que são !e não o $último. A última linha é autoprinted, mas também é a única linha em que o comando final é executada - que é a read a inteira infile novamente para stdout. Tudo isso passa pelo |tubo para o segundo, sedque só precisa deliminar de sua saída suas terceira e última linhas de entrada para concluir a reorganização.

RESULTADO:

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
mikeserv
fonte
legal, +1. Não me lembro de você ter postado awksoluções, você é um grande sedfã ou talvez tenha escrito sed? ;-)
iruvar 13/12/14
@ 1_CR - eu não sei como usar awk- eu nunca tentei. talvez um dia ...
mikeserv
2

Um método ingênuo usando o 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

Você armazena todas as linhas da amatriz e imprime a matriz na ordem que desejar (1ª linha, última ( NR) e de 2 a penúltima.

Usando uma combinação de cabeça / cauda e sed:

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

Imprima a primeira linha, a última e, com sed, exclua a primeira e a última.


Somente com o sed, só consegui encontrar este comando. Estou certo de que existem maneiras melhores:

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

Se for a primeira linha, imprima-a (padrão).
Na segunda linha, coloque-o no buffer de espera ( H) e exclua-o do espaço do padrão ( d). E se for a última linha, imprima-a ( p), obtenha o buffer de espera ( x), exclua a linha vazia ( s/^\n//) e imprima-a ( p).

fredtantini
fonte
Meu primeiro instinto seria usar o método da cabeça / cauda. Uma alternativa para a sedpeça seria algo parecido head -n -1 f | tail -n +2.
Sparhawk
@Sparhawk a -1sintaxe, pois headnão é portátil.
mikeserv
1

Com perl:

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

Com awk:

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

RESULTADO

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
Gilles Quenot
fonte