Ripeti ogni riga più volte


17

Vorrebbe che ogni riga di un file fosse ripetuta un numero fisso di volte.

ad esempio, ogni riga viene ripetuta quattro volte:

a
b
c

diventa:

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

Ho fatto qualche ricerca, e ci sono molte domande e risposte sulla falsariga di fare il contrario, ad esempio unendo le linee duplicate in singole linee e forse alcune su come raddoppiare le linee stampandole di nuovo.

Sarebbe facile farlo in C, ma mi piacerebbe sapere di più sui comandi nativi, quindi non dovrei ricorrere a questo tipo di gettate una tantum per tutto il tempo.

Risposte:


19
  • Perl:

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

    e devo aggiungere questo pubblicato come commento di @derobert perché è semplicemente fantastico:

    perl -ne 'print "$_" x4'
  • awk e varianti:

    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 fornon ha bisogno di parentesi graffe se v'è un solo comando da ripetere. E perlè più semplice se si utilizza foreachciclo: for$i(0..3){print}.
arte

4
Perl Alternativa: perl -ne 'print(($_)x4)'. Inoltre, dovresti citare $line(in eco) nella tua versione bash.
derobert il

Nel mio caso avevo bisogno delle terminazioni di linea di Windows. come visto qui può raggiungere conBEGIN { ORS="\r\n" }
Il pisello rosso

34

Mi chiedo se questo si sta trasformando in una partita di golf :

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

Spiegazione:

Il pcomando di sed è di stampare la riga corrente. Il comportamento predefinito è stampare la riga corrente appena prima di passare alla riga successiva (ecco perché sed deve -npermetterti di disattivarla). Alcune sed più vecchie non hanno il punto e virgola (penso) quindi è possibile che tu debba farlosed -e p -e p -e p

Awk funziona con le condition {action}coppie. Se l'azione viene omessa, l'impostazione predefinita è stampare la riga corrente se la condizione ritorna vera. Awk, come molti linguaggi simili a C, considera 1vero. (Per completezza, se la condizione viene omessa, l'azione verrà eseguita per ogni record.)

Molte funzioni perl sfruttano la variabile "default". Questo one-liner equivale a (su 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, se lo è, stai vincendo :) Cosa fa esattamente 1in awk? Stenografia per print $0?
terdon

3
Le istruzioni Awk sono costituite da una condizione e un blocco, o sono facoltativi, ma uno deve essere presente. La condizione predefinita è 1(true); il blocco predefinito è equivalente a {print}. Quindi l'istruzione 1significherebbe stampare il buffer di riga corrente ( {print}). ( {print}e {print $0}sono quasi sempre gli stessi, qed.)
Arcege,

Non ho mai sentito parlare di un carattere sedche non supporta i punti e virgola come terminatori di comando; c'è davvero una cosa del genere?
Wildcard


4

È possibile farlo senza la necessità 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>

Esempi

per loop
$ for i in `cat sample.txt` ; do seq 1 3 | xargs -i -- echo $i ; done
a
a
a
b
b
b
c
c
c
mentre loop
$ while read i; do seq 1 2| xargs -i -- echo $i;done < sample.txt
a
a
b
b
c
c

Penso che la versione del ciclo for si interromperà su tutte le righe contenenti spazi bianchi, quindi il ciclo while dovrebbe essere preferito. Altrimenti, +1 dato che sono un fanatico delle soluzioni shell.
evilsoup,

@evilsoup - sì, qualcun altro ha menzionato anche questo su un codice che ho pubblicato in un'altra domanda e risposta. Penso che sia il vantaggio principale di while over for, il ciclo while è tollerante al separatore $ IFS e si dividerà alla fine della linea mentre for for si divide su $ IFS.
slm

1

Usando puramente shell:

repeats=4
while read line; do yes $line|head --lines=$repeats; done < infile > outfile

Qualcuno sa come fare sì che si consideri --helpuna stringa anziché un'opzione? [considera il caso in cui si linetrova --helpo un'altra opzione]
user176581

sì,yes -- --help
don_crissti,

Usare yese headsignifica che questo non è "puramente shell"
Glenn Jackman,

1

Questo potrebbe funzionare per te (GNU sed):

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

Ripeterà ogni riga 4 volte.

O se preferisci:

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

Dove ripeti ogni riga altre 3 volte.


1

La risposta di @potong non funziona con righe vuote, la sostituzione \+con *dovrebbe risolverlo:

sed 'h;:a;s/[^\n]*/&/4;t;G;ba' file
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.