Pregunta

Tengo algunos datos en una sola línea como abajo

abc edf xyz rfg yeg udh

Quiero presentar los datos de la siguiente manera

abc
xyz
yeg


edf
rfg
udh

para que los campos alternativos se impriman con una nueva línea separada. ¿Hay algún revestimiento para esto?

¿Fue útil?

Solución

La siguiente secuencia de comandos awk puede hacerlo:

> 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

Otros consejos

Python con el mismo espíritu que el awk anterior (4 líneas):

$ 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'

Python 1-liner (omitiendo la tubería que es idéntica):

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

Otra versión de 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;

Una pena que las respuestas anteriores de perl sean tan largas. Aquí hay dos perl one-liners:

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

En versiones anteriores de perl (sin " say "), puede usar esto:

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

Solo para comparar, aquí hay algunos scripts de Perl para hacerlo (TMTOWTDI, después de todo). Un 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";

También podríamos hacerlo más cerca del 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;

Me he quedado sin formas de hacerlo, así que si algún otro Perler inteligente encuentra otro método, siéntase libre de agregarlo.

Otra solución de 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], '');
}

Incluso podría condensarlo en una sola línea 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], "");'

Aquí está la versión awk demasiado literal, no escalable y ultracorta:

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

Un poco más largo (dos caracteres más), utilizando bucles anidados (imprime una nueva línea adicional al final):

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

No imprime una nueva línea adicional:

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

Para comparación, la versión de paxdiablo con todos los caracteres innecesarios eliminados (1, 9 u 11 caracteres más):

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

Aquí hay una versión completa de 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

Mi intento en 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>

también podrías usar tr: echo "abc edf xyz rfg yeg udh" | tr ' ' '\n'

Versiones de Ruby para comparación:

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 las nuevas líneas, te dejo que lo hagas tú mismo.

Aquí hay otra forma, usando Bash, para reorganizar manualmente las palabras en una línea, con conversión previa a una matriz:

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 

¡Salud!

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top