Pegue duas colunas em um arquivo delimitado por tabulações e mescle em uma

6

Eu queria saber como eu usaria os dados que estavam nesse formato como um arquivo delimitado por tabulação:

A  red     green  
B  yellow  orange  
C  blue    purple  

E para usar comandos como grep, paste, cut, cat, etc. para transformá-lo em:

A red
B yellow
C Blue
A green
B orange
C purple
    
por NKR1 14.02.2017 / 11:18

4 respostas

8

Similar ao corte, você também pode fazer isso com o awk:

$ awk '{print $1,$2}' aa.txt && awk '{print $1,$3}' aa.txt
A red
B yellow
C blue
A green
B orange
C purple
# OR to send the output in a new file:
$ (awk '{print $1,$2}' aa.txt && awk '{print $1,$3}' aa.txt) >aaa.txt

A diferença é que o awk manipula melhor o espaço em branco do que o corte. Isso é útil se os campos de cada linha estiverem separados por mais de um espaço.

Por exemplo, se a linha do arquivo for A red = um espaço separado, a solução de corte, conforme recomendado, também poderá ser executada com êxito, mas se a linha for A red = 3 espaços, o corte falhará, enquanto o awk será bem-sucedido para obter os campos 1 e 2 ou os campos 1 e 3.

Atualização:
Como recomendado nos comentários (obrigado don_crissti) isto também pode ser feito em awk puro:

awk 'BEGIN{FS=OFS=" "}{z[NR]=$1FS$3; print $1,$2}END{for (i=1; i<=NR; i++){print z[i]}}' a.txt

Explicação:

FS           : Input Field Separator
OFS          : Output Field Separator
FS=OFS=" "   : input & output field separator is set to "space"
z[NR]        : Creating an array with name 'z' and index the record number: 
             z[1] for first line, z[2] for second line , z[3] for third line
z[NR]=$1FS$3 : to each array element assign field1-FieldSeparator FS=space)-field2
So for first line the fields1=A and Fields 3=green will be stored in z[1] => equals to z[1]="A green"

print $1,$2  : Justs prints on screen 1stfield (A) and 2ndfield (red) of the current line, printed separated by OFS

When the file is finished (END) then with a for loop we print out the whole z array entries => print z[i]
For i=1 => print z[1] => prints "A green"
For i=2 => print z[2] => prints "B orange"
For i=3 => print z[3] => prints "C purple"

PS: If fields are not separated by space but by tab , then Begin section of this awk one-liner must be changed to 'awk 'BEGIN {FS=OFS="\t"}....'
    
por 14.02.2017 / 12:31
4

Usando apenas cut , se você não se importar em escrever no arquivo (copie o arquivo original primeiro se precisar), use:

$ cut -f 1,3 file >> file && cut -f 1,2 file
A   red
B   yellow
C   blue
A   green  
B   orange  
C   purple 

Explicação

  • cut -f 1,3 file imprime a primeira e a terceira colunas de file (que são delimitadas por tabulações)
  • >> file acrescenta a saída a file em vez de exibir no terminal
  • && se isso funcionou faça o próximo comando
  • cut -f 1,2 file imprime somente a primeira e a segunda colunas de file no terminal.

Note que file acaba ficando assim:

A   red     green  
B   yellow  orange  
C   blue    purple  
A   green  
B   orange  
C   purple  

para obter o resultado final desejado em um arquivo, você precisa redirecionar para um novo arquivo.

cut -f 1,3 file >> file && cut -f 1,2 file > file2
    
por 14.02.2017 / 11:46
3

Semelhante à solução da Zanna, mas sem um arquivo / resultado intermediário:

$ ( cut -f1,2 data && cut -f1,3 data ) >data.new

A saída do subshell é pet no arquivo final data.new . O subshell primeiro extrai as duas primeiras colunas e, em seguida, a primeira e a terceira coluna.

    
por 14.02.2017 / 16:29
3
awk '{print 1 $1,$2; print 2 $1,$3}' ex |sort |cut -c 2-

Atualização: para garantir que o pedido seja mantido:

awk '{print 1,$1,$2; print 2,$1,$3}' ex |sort -sk1,1 |cut -c 3-
  • sort -sk1,1 para ter a primeira classificação de campo estável

(\ thanks {Kusalananda})

    
por 14.02.2017 / 14:25