Répétez chaque ligne plusieurs fois

17

Souhaiterait que chaque ligne d'un fichier soit répétée un nombre fixe de fois.

Par exemple, faites répéter chaque ligne quatre fois:

a
b
c

devient:

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

J'ai fait quelques recherches, et il y a beaucoup de questions et réponses dans le sens inverse, par exemple la fusion de lignes en double en lignes simples, et peut-être quelques-unes sur le doublage des lignes en les imprimant à nouveau.

Ce serait facile de le faire en C, mais j'aimerais en savoir plus sur les commandes natives pour ne pas avoir à recourir à ce genre de lancers ponctuels tout le temps.

Yimin Rong
la source

Réponses:

19
  • Perl:

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

    et je dois ajouter celui-ci posté comme commentaire par @derobert car il est juste cool:

    perl -ne 'print "$_" x4'
  • awk et 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
la source
1
awk« s fordoit pas accolades s'il n'y a qu'une seule commande à répéter. Et perlest plus simple si vous utilisez la foreachboucle: for$i(0..3){print}.
manatwork
4
Perl Alternative: perl -ne 'print(($_)x4)'. Vous devez également citer $line(en écho) dans votre version bash.
derobert
Dans mon cas, j'avais besoin de fins de ligne Windows. comme on peut le voir ici peut atteindre avecBEGIN { ORS="\r\n" }
The Red Pea
34

Je me demande si cela se transforme en match de golf :

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

Explication:

La pcommande de sed est d'imprimer la ligne courante. Le comportement par défaut consiste à imprimer la ligne actuelle juste avant de passer à la ligne suivante (c'est pourquoi sed doit -nvous permettre de la désactiver). Certains anciens seds n'ont pas le point-virgule (je pense), il est donc possible que vous deviez fairesed -e p -e p -e p

Awk fonctionne avec des condition {action}paires. Si l'action est omise, la valeur par défaut est d'imprimer la ligne actuelle si la condition renvoie true. Awk, comme de nombreux langages de type C, est considéré 1comme vrai. (Pour être complet, si la condition est omise, l'action sera exécutée pour chaque enregistrement.)

De nombreuses fonctions perl profitent de la variable "default". Ce one-liner est équivalent à (sur 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
la source
1
+1, si c'est le cas, vous gagnez :) Que fait exactement le 1awk? Sténographie pour print $0?
terdon
3
Les instructions awk sont constituées d'une condition et d'un bloc, les deux sont facultatifs, mais un doit être présent. La condition par défaut est 1(true); le bloc par défaut est équivalent à {print}. Donc, l'instruction 1signifierait imprimer le tampon de ligne actuel ( {print}). ( {print}et{print $0} sont pour la plupart les mêmes, qed.)
Arcege
Je n'ai jamais entendu parler d'un sedqui ne prend pas en charge les points-virgules comme terminateurs de commande; existe-t-il vraiment une telle chose?
Wildcard
4
sed -n '{p;p;p;p;}' file

awk '{print;print;print;print;}' file
Hauke ​​Laging
la source
4

Vous pouvez le faire sans qu'il soit nécessaire sed, perlou awk.

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

ou en utilisant une boucle while:

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

Exemples

pour boucle
$ for i in `cat sample.txt` ; do seq 1 3 | xargs -i -- echo $i ; done
a
a
a
b
b
b
c
c
c
en boucle
$ while read i; do seq 1 2| xargs -i -- echo $i;done < sample.txt
a
a
b
b
c
c
slm
la source
Je pense que la version de la boucle for se cassera sur toutes les lignes contenant des espaces, donc la boucle while devrait être préférée. Sinon, +1 puisque je suis un aspirant pour les solutions shell.
evilsoup
@evilsoup - oui, quelqu'un d'autre l'a également mentionné sur un code que j'ai publié sur une autre Q&R. Je pense que c'est le principal avantage de while over for, la boucle while est tolérante du séparateur $ IFS et se divisera en fin de ligne tandis que le for se divisera sur $ IFS.
slm
1

Utilisation purement shell:

repeats=4
while read line; do yes $line|head --lines=$repeats; done < infile > outfile
user176581
la source
Est-ce que quelqu'un sait comment faire en sorte que yes soit considéré --helpcomme une chaîne plutôt qu'une option? [considérez le cas où lineest --helpou une autre option]
user176581
oui,yes -- --help
don_crissti
Utiliser yeset headsignifie que ce n'est pas "purement shell"
glenn jackman
1

Cela pourrait fonctionner pour vous (GNU sed):

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

Répétera chaque ligne 4 fois.

Ou si vous préférez:

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

Où vous répétez chaque ligne 3 fois de plus.

potong
la source
1

La réponse de @potong ne fonctionne pas avec des lignes vides, le remplacer \+par *devrait le corriger:

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