Pergunta

Eu tenho alguns dados em uma única linha como abaixo

abc edf xyz rfg yeg udh

Eu quero apresentar os dados como abaixo

abc
xyz
yeg


edf
rfg
udh

de modo que os campos alternados são impressos com nova linha separada. Há algum forros para isso?

Foi útil?

Solução

O script a seguir awk pode fazê-lo:

> echo 'abc edf xyz rfg yeg udh' | awk '{
    for (i = 1;i<=NF;i+=2){print $i}
    print "";
    for (i = 2;i<=NF;i+=2){print $i}
    }'
abc
xyz
yeg

edf
rfg
udh

Outras dicas

Python com o mesmo espírito como o awk acima (4 linhas):

$ echo 'abc edf xyz rfg yeg udh' | python -c 'f=raw_input().split()
> for x in f[::2]: print x
> print
> for x in f[1::2]: print x'

pitão 1-forro (omitindo-se o tubo a ele o qual é idêntico):

$ python -c 'f=raw_input().split(); print "\n".join(f[::2] + [""] + f[1::2])'

Outra versão Perl 5:

#!/usr/bin/env perl
use Modern::Perl;
use List::MoreUtils qw(part);

my $line = 'abc edf xyz rfg yeg udh';

my @fields = split /\s+/, $line; # split on whitespace

# Divide into odd and even-indexed elements
my $i = 0;
my ($first, $second) = part { $i++ % 2 }  @fields;

# print them out
say for @$first;
say '';          # Newline
say for @$second;

Uma vergonha que as respostas perl anteriores são tão longas. Aqui estão dois Perl one-liners:

echo 'abc edf xyz rfg yeg udh'|
  perl -naE '++$i%2 and say for @F; ++$j%2 and say for "",@F'

Em versões mais antigas do perl (sem "dizer"), você pode usar isto:

echo 'abc edf xyz rfg yeg udh'|
  perl -nae 'push @{$a[++$i%2]},"$_\n" for "",@F; print map{@$_}@a;'

Apenas para comparação, a seguir, alguns scripts Perl para fazê-lo (TMTOWTDI, depois de tudo). Um estilo bastante funcional:

#!/usr/bin/perl -p

use strict;
use warnings;

my @a = split;
my @i = map { $_ * 2 } 0 .. $#a / 2;
print join("\n", @a[@i]), "\n\n",
      join("\n", @a[map { $_ + 1 } @i]), "\n";

Nós também poderia fazê-lo mais perto para o script AWK:

#!/usr/bin/perl -p

use strict;
use warnings;

my @a = split;
my @i = map { $_ * 2 } 0 .. $#a / 2;
print "$a[$_]\n" for @i;
print "\n";
print "$a[$_+1]\n" for @i;

Já corri para fora de maneiras de fazer isso, então se quaisquer outros Perlers inteligentes vir para cima com outro método, fique à vontade para adicioná-lo.

Outra solução Perl:

use strict;
use warnings;

while (<>)
{
    my @a = split;
    my @b = map { $a[2 * ($_%(@a/2)) + int($_ / (@a /2))]  . "\n" } (0 .. @a-1); 
    print join("\n", @a[0..((@b/2)-1)], '', @a[(@b/2)..@b-1], '');
}

Você até poderia condensá-lo em um one-liner real:

perl -nwle'my @a = split;my @b = map { $a[2 * ($_%(@a/2)) + int($_ / (@a /2))]  . "\n" } (0 .. @a-1);print join("\n", @a[0..((@b/2)-1)], "", @a[(@b/2)..@b-1], "");'

Aqui está o demasiado literal, não escalável, versão awk ultra-curto:

awk '{printf "%s\n%s\n%s\n\n%s\n%s\n%s\n",$1,$3,$5,$2,$4,$6}'

ligeiramente mais longa (mais dois caracteres), utilizando laços aninhados (imprime uma nova linha extra no final):

awk '{for(i=1;i<=2;i++){for(j=i;j<=NF;j+=2)print $j;print ""}}'

Não imprime uma nova linha extra:

awk '{for(i=1;i<=2;i++){for(j=i;j<=NF;j+=2)print $j;if(i==1)print ""}}'

Para comparação, paxdiablo 's versão com todos os caracteres desnecessários removidos (1, 9 ou mais 11 caracteres):

awk '{for(i=1;i<=NF;i+=2)print $i;print "";for(i=2;i<=NF;i+=2)print $i}'

Aqui está uma versão todo-Bash:

d=(abc edf xyz rfg yeg udh)
i="0 2 4 1 3 5"
for w in $i
do
    echo ${d[$w]}
    [[ $w == 4 ]]&&echo
done

Minha tentativa em Haskell:

Prelude> (\(x,y) -> putStr $ unlines $ map snd (x ++ [(True, "")] ++ y)) $ List.partition fst $ zip (cycle [True, False]) (words "abc edf xyz rfg yeg udh")
abc
xyz
yeg

edf
rfg
udh
Prelude>

Você também pode usar apenas tr: echo "abc edf xyz rfg yeg udh" | tr ' ' '\n'

versões Ruby para comparação:

ARGF.each do |line|
  groups = line.split
  0.step(groups.length-1, 2) { |x| puts groups[x] }
  puts
  1.step(groups.length-1, 2) { |x| puts groups[x] }
end

ARGF.each do |line|
  groups = line.split
  puts groups.select { |x| groups.index(x) % 2 == 0 }
  puts
  puts groups.select { |x| groups.index(x) % 2 != 0 }
end
$ echo 'abc edf xyz rfg yeg udh' |awk -vRS=" " 'NR%2;NR%2==0{_[++d]=$0}END{for(i=1;i<=d;i++)print _[i]}'
abc
xyz
yeg
edf
rfg
udh

Para novas linhas, eu deixá-lo para que você faça a si mesmo.

Aqui está ainda outra forma, usando Bash, às palavras manualmente Reorganizar em uma linha - com a conversão anterior para um array:

echo 'abc edf xyz rfg yeg udh' | while read tline; do twrds=($(echo $tline)); echo -e "${twrd[0]} \n${twrd[2]} \n${twrd[4]} \n\n ${twrd[1]} \n${twrd[3]} \n${twrd[5]} \n" ; done 

Felicidades!

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top