Repite cada línea varias veces

17

Me gustaría tener cada línea en un archivo repetido un número fijo de veces.

Por ejemplo, que cada línea se repita cuatro veces:

a
b
c

se convierte en:

a
a
a
a
b
b
b
b
c
c
c
c

He realizado algunas búsquedas, y hay muchas preguntas y respuestas en el sentido de hacer lo contrario, por ejemplo, fusionar líneas duplicadas en líneas individuales, y tal vez algunas sobre duplicar líneas imprimiéndolas nuevamente.

Sería fácil hacer esto en C, pero desearía saber más sobre los comandos nativos para no tener que recurrir a este tipo de descartes todo el tiempo.

Yimin Rong
fuente

Respuestas:

19
  • Perl:

    perl -ne 'for$i(0..3){print}' file

    y tengo que agregar este publicado como comentario por @derobert porque es genial:

    perl -ne 'print "$_" x4'
  • awk y variantes:

    awk '{for(i=0;i<4;i++)print}' file
  • bash

    while read line; do for i in {1..4}; do echo "$line"; done; done < file
terdon
fuente
1
awk's forno necesita apoyos si sólo hay un comando para repetir. Y perles más sencillo si se utiliza foreachen bucle: for$i(0..3){print}.
manatwork
44
Perl alternativa: perl -ne 'print(($_)x4)'. Además, debe citar $line(en eco) en su versión bash.
derobert
En mi caso, necesitaba finales de línea de Windows. como se ve aquí puede lograr conBEGIN { ORS="\r\n" }
The Red Pea
34

Me pregunto si esto se está convirtiendo en un partido de golf :

sed 'p;p;p' 
awk '1;1;1;1' 
perl -lpE 'say;say;say'   # if Paul McCartney and Michael Jackson were hackers...

Explicación:

sed's p comando es imprimir la línea actual. El comportamiento predeterminado es imprimir la línea actual justo antes de pasar a la siguiente línea (es por eso que sed tiene -nque permitirle desactivarla). Algunos seds más antiguos no tienen punto y coma (creo), por lo que es posible que tenga que hacersed -e p -e p -e p

Awk trabaja con condition {action} pares. Si se omite la acción, el valor predeterminado es imprimir la línea actual si la condición devuelve verdadero. Awk, como muchos lenguajes tipo C, se trata 1como verdadero. (Para completar, si se omite la condición, la acción se ejecutará para cada registro).

Muchas funciones perl aprovechan la variable "predeterminada". Esta línea es equivalente a (en perl 5.16):

$ perl -MO=Deparse -lpE 'say;say;say'
BEGIN { $/ = "\n"; $\ = "\n"; }
use feature 'current_sub', 'evalbytes', 'fc', 'say', 'state', 'switch', 'unicode_strings', 'unicode_eval';
LINE: while (defined($_ = <ARGV>)) {
    chomp $_;
    say $_;
    say $_;
    say $_;
}
continue {
    die "-p destination: $!\n" unless print $_;
}
Glenn Jackman
fuente
1
+1, si es así, estás ganando :) ¿Qué hace exactamente 1en awk? Taquigrafía para print $0?
terdon
3
Las declaraciones Awk están formadas por una condición y un bloque, ambos son opcionales, pero uno debe estar presente. La condición predeterminada es 1(verdadera); El bloque predeterminado es equivalente a {print}. Entonces, la declaración 1significaría imprimir el búfer de línea actual ( {print}). ( {print}y {print $0}son casi lo mismo, qed.)
Arcege
Nunca he oído hablar de un sedque no admite punto y coma como terminadores de comando; ¿Realmente hay tal cosa?
Comodín
4
sed -n '{p;p;p;p;}' file

awk '{print;print;print;print;}' file
Hauke ​​Laging
fuente
4

Esto se puede hacer sin que se requiera sed, perlo awk.

$ for i in `cat <file>` ; do seq <#> <#> | xargs -i -- echo $i ; done

o usando un ciclo while:

$ while read i ; do seq <#> <#> | xargs -i -- echo $i ; done < <file>

Ejemplos

en bucle
$ for i in `cat sample.txt` ; do seq 1 3 | xargs -i -- echo $i ; done
a
a
a
b
b
b
c
c
c
mientras bucle
$ while read i; do seq 1 2| xargs -i -- echo $i;done < sample.txt
a
a
b
b
c
c
slm
fuente
Creo que la versión del bucle for se romperá en cualquier línea que contenga espacios en blanco, por lo que debería preferirse el bucle while. De lo contrario, +1 ya que soy un fanático de las soluciones de shell.
evilsoup
@evilsoup: sí, alguien más mencionó esto también en algún código que publiqué en otras preguntas y respuestas. Creo que esa es la principal ventaja de while over for, el while while es tolerante al separador $ IFS y se dividirá al final de la línea, mientras que for se divide en $ IFS.
slm
1

Usando puramente shell:

repeats=4
while read line; do yes $line|head --lines=$repeats; done < infile > outfile
usuario176581
fuente
¿Alguien sabe cómo hacer que sí se considere --helpcomo una cadena en lugar de una opción? [considere el caso donde lineestá --helpu otra opción]
user176581
sí,yes -- --help
don_crissti
Usar yesy headsignifica que esto no es "puramente shell"
glenn jackman
1

Esto podría funcionar para usted (GNU sed):

sed 'h;:a;s/[^\n]\+/&/4;t;G;ba' file

Repetirá cada línea 4 veces.

O si lo prefieres:

sed 'h;:a;s/\n/&/3;t;G;ba' file

Donde repites cada línea 3 veces más.

potong
fuente
1

La respuesta de @potong no funciona con líneas vacías, reemplazar \+con *debería solucionarlo:

sed 'h;:a;s/[^\n]*/&/4;t;G;ba' file
Jan Kos
fuente