Powtórz każdą linię wiele razy

17

Chciałbym, aby każda linia w pliku była powtarzana określoną liczbę razy.

np. niech każda linia powtórzy się cztery razy:

a
b
c

staje się:

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

Przeszukałem kilka stron i jest wiele pytań i odpowiedzi na odwrót, np. Łączenie zduplikowanych linii w pojedyncze linie, a może kilka na temat podwajania linii poprzez ich ponowne wydrukowanie.

Łatwo byłoby to zrobić w C, ale chciałbym wiedzieć więcej o natywnych poleceniach, więc nie musiałbym uciekać się do tego rodzaju jednorazowych rzutów.

Yimin Rong
źródło

Odpowiedzi:

19
  • Perl:

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

    i muszę dodać ten opublikowany jako komentarz przez @derobert, ponieważ jest po prostu fajny:

    perl -ne 'print "$_" x4'
  • awk i warianty:

    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
źródło
1
awk„s fornie potrzebuje szelki, jeśli jest tylko jedno polecenie, aby powtórzyć. I perljest prostsze, jeśli używasz foreachpętli: for$i(0..3){print}.
manatwork
4
Alternatywą Perl: perl -ne 'print(($_)x4)'. Powinieneś również cytować $line(w echu) w swojej wersji bash.
derobert
W moim przypadku potrzebowałem zakończenia linii Windows. jak widać tutaj można osiągnąć za pomocąBEGIN { ORS="\r\n" }
The Red Pea
34

Zastanawiam się, czy to zamienia się w mecz golfowy :

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

Wyjaśnienie:

pPoleceniem sed jest wydrukowanie bieżącej linii. Domyślnym zachowaniem jest wydrukowanie bieżącej linii tuż przed przejściem do następnej linii (dlatego sed musi -npozwolić ci ją wyłączyć). Niektóre starsze sedy nie mają średnika (tak myślę), więc możliwe, że będziesz musiał to zrobićsed -e p -e p -e p

Awk działa z condition {action}parami. Jeśli akcja zostanie pominięta, domyślnie drukowany jest bieżący wiersz, jeśli warunek zwraca wartość true. Awk, podobnie jak wiele języków podobnych do C, traktuje 1jako prawdę. (Dla kompletności, jeśli warunek zostanie pominięty, akcja zostanie wykonana dla każdego rekordu).

Wiele funkcji perla wykorzystuje zmienną „domyślną”. Ten liniowiec jest równoważny (na 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
źródło
1
+1, jeśli tak, wygrywasz :) Co dokładnie robi 1awk? Stenografia dla print $0?
terdon
3
Instrukcje Awk składają się z warunku i bloku, albo są opcjonalne, ale jeden musi być obecny. Domyślnym warunkiem jest 1(prawda); domyślny blok jest równoważny z {print}. Tak więc instrukcja 1oznaczałaby wydrukowanie bieżącego bufora linii ( {print}). ( {print}i {print $0}są w większości takie same, qed.)
Arcege
Nigdy nie słyszałem o tym, sedże nie obsługuje średników jako terminatorów poleceń; czy naprawdę jest coś takiego?
Wildcard
4
sed -n '{p;p;p;p;}' file

awk '{print;print;print;print;}' file
Hauke ​​Laging
źródło
4

Można to zrobić bez potrzeby sed, perllub awk.

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

lub za pomocą pętli while:

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

Przykłady

dla pętli
$ for i in `cat sample.txt` ; do seq 1 3 | xargs -i -- echo $i ; done
a
a
a
b
b
b
c
c
c
pętla while
$ while read i; do seq 1 2| xargs -i -- echo $i;done < sample.txt
a
a
b
b
c
c
slm
źródło
Myślę, że wersja for pęka na wszystkich liniach zawierających białe spacje, więc powinna być preferowana pętla while. W przeciwnym razie +1, ponieważ jestem frajerem rozwiązań powłoki.
evilsoup
@evilsoup - tak, ktoś inny wspominał o tym również w kodzie, który opublikowałem w innym pytaniu i odpowiedziach. Myślę, że to podstawowa zaleta „over over”, pętla while toleruje separator $ IFS i dzieli się na końcu linii, podczas gdy for dzieli na $ IFS.
slm
1

Używając wyłącznie powłoki:

repeats=4
while read line; do yes $line|head --lines=$repeats; done < infile > outfile
użytkownik176581
źródło
Czy ktoś wie, jak sprawić, aby tak traktował --helpjako ciąg zamiast opcji? [rozważ przypadek, w którym linejest --helplub inna opcja]
user176581,
tak,yes -- --help
don_crissti,
Używając yesi headoznacza to, że nie jest to „czysto skorupa”
glenn jackman
1

To może Ci pomóc (GNU sed):

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

Powtórzy każdą linię 4 razy.

Lub jeśli wolisz:

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

Gdzie powtórzysz każdą linię jeszcze 3 razy.

potong
źródło
1

Odpowiedź @potong nie działa z pustymi liniami, zastąpienie \+przez *powinno to naprawić:

sed 'h;:a;s/[^\n]*/&/4;t;G;ba' file
Jan Kos
źródło