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.

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

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 $_;
}

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

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

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

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.


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
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.