Como faço para transpor uma linha para uma coluna em um arquivo delimitado por tabulação?

3

Eu tenho um arquivo delimitado por tabulações com um número e os nomes pertencentes ao mesmo número na mesma linha. O número e os nomes são separados por uma guia. Os nomes estão ligados entre si por dois sublinhados ( __ ). Parece assim:

33  Hhe.1__Hhe.2__Hhe.3__Hhe.4

Eu gostaria de convertê-lo (usando a linha de comando) para esta saída:

33  Hhe.1
33  Hhe.2
33  Hhe.3
33  Hhe.4
    
por Annemieke Smet 12.04.2016 / 11:07

5 respostas

6

com awk :

$ awk -F '\t|__' '{for (i=2;i<=NF;i++) {printf "%s\t%s\n", $1, $i}}' foo.txt 
33  Hhe.1
33  Hhe.2
33  Hhe.3
33  Hhe.4
  • Divide as linhas em campos com base na guia ( \t ) ou em dois sublinhados ( __ ).
  • Em seguida, percorremos os campos do segundo até o último e imprimimos cada prefixo com o primeiro campo e uma tabulação.
por muru 12.04.2016 / 11:21
4

Você pode usar um perl one-liner para isso:

perl -ane '@l=split(/__/,$F[1]); foreach $val (@l){print $F[0],"\t",$val,"\n"}'

Exemplo:

$ echo "33  Hhe.1__Hhe.2__Hhe.3__Hhe.4" | perl -ane '@l=split(/__/,$F[1]); foreach $val (@l){print $F[0],"\t",$val,"\n"}'
33  Hhe.1
33  Hhe.2
33  Hhe.3
33  Hhe.4

Explicação dos comandos usados:

perl -ane                    #read input line-wise and split line on tab
'@l=split(/__/,$F[1]);       #split the second element ($F[1]) on a double _
foreach $val (@l){           #for each value, print the first element and the value.
  print $F[0],"\t",$val,"\n"
 }'
    
por Wayne_Yux 12.04.2016 / 11:21
3

Outra maneira de usar o Perl:

perl -lane '$,="\n"; print(map($F[0] . "\t" . $_, split("__", $F[1])))' file
perl -lane '
    $,="\n";
    print(map($F[0] . "\t" . $_, split("__", $F[1])))
' file
  • -l[octnum] : ativa o processamento automático de finalização de linha. Tem dois efeitos separados. Primeiro, ele automaticamente copia $/ (o separador de registro de entrada) quando usado com -n ou -p . Segundo, ele designa $\ (o separador de registro de saída) para ter o valor de octnum, de forma que quaisquer instruções de impressão tenham esse separador novamente incluído. Se octnum for omitido, define $\ para o valor atual de $/ .
  • -a : ativa o modo de preenchimento automático quando usado com -n ou -p . Um comando de divisão implícito para o array @F é feito como a primeira coisa dentro do loop while implícito produzido pelo -n ou -p .
  • -n : faz com que o Perl assuma o seguinte loop em torno do seu programa, o que faz com que seja iterado sobre argumentos de nome de arquivo parecidos com sed -n ou awk :

    LINE:
      while (<>) {
          ...             # your program goes here
      }
    
  • -e : pode ser usado para inserir uma linha do programa;

  • %código%; define o separador de campo de saída para um caractere de nova linha, divide o segundo campo em $,="\n"; print(map($F[0] . "\t" . $_, split("__", $F[1]))) e preenche o primeiro campo seguido por uma tabulação para cada subcampo, finalmente imprimindo o registro.
% cat file
33  Hhe.1__Hhe.2__Hhe.3__Hhe.4
% perl -lane '$,="\n"; print(map($F[0] . "\t" . $_, split("__", $F[1])))' file
33  Hhe.1
33  Hhe.2
33  Hhe.3
33  Hhe.4
    
por kos 12.04.2016 / 11:27
1

Ainda outro perl one-liner:

$ perl -lane 'print "$F[0]\t$_" for split(/__/,$F[1])' file 
33  Hhe.1
33  Hhe.2
33  Hhe.3
33  Hhe.4

Esta é a mesma ideia básica que o Perl existente responde, apenas mais curta. O -a divide automaticamente cada linha do arquivo de entrada em espaços em branco e disponibiliza os campos resultantes como a matriz @F . Então, $F[0] é o primeiro campo, $F[1] o segundo e assim por diante. O -n significa "leia cada arquivo de entrada linha por linha e aplique o script fornecido por -e . O -l remove os caracteres \n finais de cada linha de entrada e adiciona \n a cada print .

split(/__/,$F[1]) cria uma matriz dividindo o primeiro campo do arquivo nos caracteres __ . Portanto, print "$F[0]\t$_" for split... iterará a matriz retornada pela chamada split e imprimirá o primeiro campo do arquivo ( $F[0] ), um caractere de tabulação \t e o campo atual da matriz split .

    
por terdon 12.04.2016 / 11:58
1

Semelhante ao que o muru sugeriu: que tal dividir o segundo campo com base em __ e, em seguida, fazer o loop pelas fatias?

awk 'BEGIN{FS=OFS="\t"}
     {n=split($2,a,"__"); for (i=1;i<=n;i++) print $1, a[i]}' file

Isso usa o fato de que split() retorna o número de elementos criados.

Além disso, ele define os separadores de campo de entrada e saída na guia, para que você não precise mencioná-lo quando você print . Na verdade, FS não precisa ser definido aqui, porque FS é padronizado para o espaço e a guia é incluída.

Ele retorna:

33  Hhe.1
33  Hhe.2
33  Hhe.3
33  Hhe.4
    
por fedorqui 12.04.2016 / 14:39