Repita cada linha várias vezes

17

Gostaria que cada linha de um arquivo fosse repetida um número fixo de vezes.

por exemplo, repetir cada linha quatro vezes:

a
b
c

torna-se:

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

Eu fiz algumas pesquisas e há muitas perguntas e respostas ao longo das linhas para fazer o inverso, por exemplo, mesclar linhas duplicadas em linhas únicas e talvez algumas sobre duplicar linhas imprimindo-as novamente.

Seria fácil fazer isso em C, mas eu gostaria de saber mais sobre os comandos nativos para não precisar recorrer a esses tipos de brincadeiras pontuais o tempo todo.

Yimin Rong
fonte

Respostas:

19
  • Perl:

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

    e eu tenho que adicionar este postado como um comentário por @derobert porque é legal:

    perl -ne 'print "$_" x4'
  • awk e 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
fonte
11
awk's fornão precisa de chaves, se houver apenas um comando para repetir. E perlé mais simples se você usar o foreachloop: for$i(0..3){print}.
Manatwork
4
Perl Alternativa: perl -ne 'print(($_)x4)'. Além disso, você deve citar $line(em eco) em sua versão do bash.
Derobert
No meu caso, eu precisava de finais de linha do Windows. como visto aqui pode conseguir comBEGIN { ORS="\r\n" }
The Red Pea
34

Gostaria de saber se isso está se transformando em uma partida de golfe :

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

Explicação:

O pcomando do sed é imprimir a linha atual. O comportamento padrão é imprimir a linha atual imediatamente antes de passar para a próxima linha (é por isso que o sed precisa -npermitir que você a desative). Alguns seds mais velhos não têm o ponto-e-vírgula (eu acho), então é possível que você precise fazersed -e p -e p -e p

O Awk trabalha com condition {action}pares. Se a ação for omitida, o padrão é imprimir a linha atual se a condição retornar verdadeira. O Awk, como muitos idiomas semelhantes a C, trata 1como verdade. (Para completar, se a condição for omitida, a ação será executada para cada registro.)

Muitas funções perl aproveitam a variável "padrão". Este one-liner é equivalente a (no 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
fonte
11
+1, se estiver, você está ganhando :) O que exatamente o 1awk faz? Taquigrafia para print $0?
terdon
3
As declarações awk são compostas de uma condição e um bloco, são opcionais, mas uma deve estar presente. A condição padrão é 1(true); o bloco padrão é equivalente a {print}. Portanto, a instrução 1significaria imprimir o buffer de linha atual ( {print}). ( {print}E {print $0}são praticamente os mesmos, qed.)
Arcege
Eu nunca ouvi falar de um sedque não suporte ponto e vírgula como terminadores de comando; existe realmente uma coisa dessas?
Wildcard
4
sed -n '{p;p;p;p;}' file

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

Você pode fazer isso sem a necessidade de sed, perlou awk.

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

ou usando um loop while:

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

Exemplos

para laço
$ for i in `cat sample.txt` ; do seq 1 3 | xargs -i -- echo $i ; done
a
a
a
b
b
b
c
c
c
enquanto loop
$ while read i; do seq 1 2| xargs -i -- echo $i;done < sample.txt
a
a
b
b
c
c
slm
fonte
Eu acho que a versão do loop for quebrará em qualquer linha que contenha espaço em branco, portanto, o loop while deve ser preferido. Caso contrário, +1, pois sou um otário para soluções de shell.
evilsoup
@evilsoup - sim, alguém mencionou isso também em algum código que eu publiquei em outra sessão de perguntas e respostas. Eu acho que essa é a principal vantagem do tempo que passou, o loop while é tolerante com o separador $ IFS e será dividido no final da linha, enquanto o for se divide no $ IFS.
Slm
1

Usando puramente shell:

repeats=4
while read line; do yes $line|head --lines=$repeats; done < infile > outfile
user176581
fonte
Alguém sabe como fazer sim considerar --helpcomo uma string em vez de uma opção? [considere o caso em que lineexiste --helpou outra opção]
user176581
sim,yes -- --help
don_crissti 13/09/2015
Usando yese headmeios isto não é "puramente shell"
Glenn Jackman
1

Isso pode funcionar para você (GNU sed):

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

Repetirá cada linha 4 vezes.

Ou se você preferir:

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

Onde você repete cada linha mais três vezes.

potong
fonte
1

A resposta do @potong não funciona com linhas vazias, substituindo \+por *deve corrigi-lo:

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