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

8

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

aaaaaa
bbbbbb
cccccc
dddddd
eeeeee

Eu preciso cortar a última linha deste arquivo e colocá-lo na segunda posição. Deve ser parecido abaixo.

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
    
por Vivek William 12.12.2014 / 15:51

4 respostas

9

Esse problema pode, na verdade, ser mais fácil de fazer com ed , já que é 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, já que ele já está fazendo isso para 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
    
por 12.12.2014 / 20:02
5

Segure o método do buffer:

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

... H old toda linha que é ! não é a primeira e a primeira p rints. Na última linha $ , e x altera os espaços de espera e padrão antes faz o H old - que recebe as linhas salvas anexadas à última linha - então d eletes de Saída de todas as linhas que são ! e não $ last.

Na última linha $ , e x altera os espaços novamente, s/// ubstitui o primeiro caractere \n ewline - que cuida do extra adicionado na linha 2 - e depois imprime automaticamente o lote.

OUTPUT:

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'

Isso redireciona <infile para o primeiro sed ' stdin , que somente p solicita a primeira linha antes de d excluir da saída todas as linhas que são ! e não $ . A última linha é autoprintada, mas também é a única linha na qual o comando final é executado - que é r todo o infile para stdout . Tudo isso é passado sobre o | pipe para o segundo sed , que então tem apenas para d elete de sua saída suas terceiras e últimas linhas de entrada para completar o rearrange.

OUTPUT:

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
    
por 13.12.2014 / 00:44
2

Uma abordagem ingênua 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 na matriz a e, em seguida, imprime a matriz na ordem desejada (1ª linha, última ( NR ) e 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 o sed, exclua a primeira e a última.

Apenas com o sed, só consegui encontrar este comando. Tenho certeza 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-a no buffer de retenção ( H ) e exclua a partir do espaço padrão ( d ). E se for a última linha, imprima-a ( p ), então pegue o buffer de retenção ( x ), exclua a linha vazia ( s/^\n// ) e imprima-a ( p ).

    
por 12.12.2014 / 16:01
1

Com perl:

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

com o awk:

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

OUTPUT

aaaaaa
eeeeee
bbbbbb
cccccc
dddddd
    
por 12.12.2014 / 16:02