Como imprimir a primeira coluna da próxima linha na linha atual?

8

Eu tenho um arquivo assim:

abc 123    
abc 789  
bcd 456  
acb 135

Eu gostaria de imprimir a primeira coluna da próxima linha na linha atual.

Saída desejada:

abc  123 abc  
abc 789 bcd  
bcd 456 acb  
acb 135 

Eu prefiro usar o awk.

    
por user2905046 12.01.2017 / 07:42

4 respostas

16

Memorize a linha anterior:

awk 'NR > 1 { print prev, $1 } { prev = $0 } END { print prev }'

Isso processa a entrada da seguinte forma:

  • se a linha atual for a segunda ou maior, imprima a linha anterior (armazenada em prev , consulte a próxima etapa) e o primeiro campo da linha atual, separado pelo separador de campo de saída (o caractere de espaço por padrão );
  • em todos os casos, armazene a linha atual na variável prev ;
  • no final do arquivo, imprima a linha anterior.
por 12.01.2017 / 08:00
10

Alternativa awk abordagem:

$ awk 'NR == 1{printf "%s", $0;next}{printf " %s\n%s", $1,$0}' input.txt                                    
abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135

A maneira como isso funciona é simples: a primeira linha é um caso especial - nós a imprimimos sem a nova linha e pedimos ao awk que vá para a próxima linha sem executar outros blocos de código. Depois disso, NR == 1{printf "%s", $0;next} é ignorado, mas outras partes fazem o trabalho.

Lembre-se de que até agora imprimimos uma string formatada sem o novo caractere de linha. Assim, o que está sendo feito por printf " %s\n%s",$1,$0 agora é a primeira palavra impressa (e porque não havia nova linha, permanece na mesma linha de saída), nova linha inserida e, em seguida, toda a própria linha (mas não termina com caractere de nova linha). Assim, a próxima primeira palavra inserida permanecerá na mesma linha. O processo continua e continua até chegarmos ao final do arquivo.

A possível melhoria é incluir o bloco END{print ""} para inserir a nova linha final. Em certos casos em que o arquivo resultante deve ser processado por outros scripts, pode ser desejável.

Embora o usuário tenha solicitado especificamente o AWK, a mesma abordagem com a impressão de strings formatadas pode ser obtida com outros idiomas, por exemplo, o Python. Alternativa em Python fornecida para aqueles curiosos sobre como isso pode ser implementado em outras linguagens:

#!/usr/bin/env python
from __future__ import print_function
import sys

old = None
for index,line in enumerate(sys.stdin):
    if index == 0:
        print(line.strip(),end=" ")
        continue
    words = line.strip().split()
    print(words[0] + "\n" + line.strip(),end=" ")

E uso assim:

$ ./append_first.py < input.txt                            
abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135

A mesma ideia sobre a nova linha final se aplica aqui.

    
por 12.01.2017 / 08:29
9

Aqui está uma maneira feia de sed apenas por diversão

sed '2,$ s/[^ ]\+/& &/; 2,$ s/ /\n/' file | paste -d ' ' - -
abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135 

Explicação

  • 2,$ da segunda linha para a última
  • s/[^ ]\+/& &/ double o primeiro conjunto de caracteres não brancos
  • ; separa comandos, como no shell
  • s/ /\n/ substitui o primeiro espaço por uma nova linha
  • paste -d ' ' - - mantém essa bagunça juntos (acrescente a segunda linha a terceira, a quarta linha a terceira, etc)
por 12.01.2017 / 09:55
1

Na minha opinião, a abordagem mais simples e mais legível é:

  1. extrai a primeira coluna ( cut )
  2. exclua a primeira linha de sua coluna extraída ( tail )
  3. cole esta coluna no seu arquivo de origem ( paste )

Exemplo: seu exemplo de arquivo inpult:

abc 123    
abc 789  
bcd 456  
acb 135

Em seguida, execute o seguinte comando em um terminal

cut -d' ' -f1 in.txt | tail -n +2 | paste -d' ' file -

Saída:

abc 123 abc
abc 789 bcd
bcd 456 acb
acb 135

A estrutura por trás dessa solução difere das respostas dadas. Não há necessidade de condições, loops ou expressão regular.

    
por 10.05.2017 / 07:19