Com tcshou zsh, repeat 5000 printf Hé mais fácil de entender. Com perl: print "H" x 5000(note que esse {1..5000}é um operador zsh inspirado por perl's 1..5000um e depois copiado por ksh93 e bash)
Stéphane Chazelas
sim ele funciona, mas usa um monte de recursos para ampliar repetição, siga as sugestões por Stéphane Chazelas
Skaperen
1
Eu faria isso de comandoyes H|head -5000|tr -d '\012'
Skaperen
dd if=/dev/zero bs=5000 count=1 | tr '\0' H
Kojiro
@Skaepren:yes H| head -n 2500| tr \\n H
mikeserv
Respostas:
20
Esse comando depende do shell gerar 5000 argumentos e passá-los aos printfquais os ignora. Embora possa parecer bastante rápido - e seja relativo a algumas coisas - o shell ainda deve gerar todas essas strings como args (e delimitá-las) e assim por diante.
Além do fato de que os Hs gerados não podem ser impressos até que o shell itere primeiro para 5000, esse comando também custa na memória tudo o que é necessário para armazenar e delimitar os argumentos de sequência numérica para printfsomar os Hs. Da mesma maneira que você pode:
printf %05000s|tr \ H
... que gera uma sequência de 5.000 espaços - que, pelo menos, geralmente são apenas um byte e não custam nada para delimitar porque não são delimitados. Alguns testes indicam que, mesmo com apenas 5000 bytes, o custo do garfo e do tubo necessário trvale a pena mesmo nesse caso, e quase sempre ocorre quando os números aumentam.
Eu corri...
time bash -c 'printf H%.0s {1..5000}'>/dev/null
...e...
time bash -c 'printf %05000s|tr \ H'>/dev/null
Cada uma cerca de 5 vezes por peça (nada de científico aqui - apenas anedótico) e a versão de expansão da cinta trtiveram em média um pouco mais de 0,02 segundos no tempo total de processamento, mas a versão chegou em média 0,012 segundos no total - e a trversão foi melhorada toda vez. Não posso dizer que estou surpreso - {brace expansion}é um recurso de taquigrafia interativo útil do shell, mas geralmente é uma coisa muito esbanjadora para se fazer em qualquer tipo de script. A forma comum:
for i in{[num]..[num]};do...
... quando você pensa sobre isso, são realmente doisfor loops - o primeiro é interno e está implícito, pois o shell deve fazer um loop de alguma maneira para gerar esses iteradores antes de salvá-los e iterá-los novamente para o seu forloop. Geralmente, essas coisas são feitas melhor como:
... porque você armazena apenas muito poucos valores e os substitui à medida que avança, além de fazer a iteração enquanto gera os iteráveis.
De qualquer forma, como o preenchimento de espaço mencionado anteriormente, você também pode usar printfpara zeropar um número arbitrário de dígitos, é claro, como:
printf %05000d
Faço as duas coisas sem argumentos, porque para cada argumento especificado na printfstring de formato de um argumento, quando não é encontrado, a string nula é usada - que é interpretada como zero para um argumento de dígito ou vazia para uma string.
Esse é o outro lado (e - na minha opinião - mais eficiente) da moeda quando comparado com o comando da pergunta - embora seja possível não obter nada de algo como você faz ao printf %.0estender as seqüências de caracteres para cada argumento, também é é possível obter algo do nada.
Ainda mais rápido para grandes quantidades de bytes gerados, você pode usar ddcomo:
printf \\0| dd bs=64k conv=sync
... e ddo seek=[num]argumento de arquivos regulares pode ser usado para maior vantagem. Você pode obter novas linhas de 64k em vez de nulas se adicionar as opções ,unblock cbs=1acima e a partir daí poderá injetar seqüências arbitrárias por linha com pastee /dev/null- mas nesse caso, se estiver disponível, você também poderá usar:
yes 'output string forever'
Aqui estão mais alguns ddexemplos de qualquer maneira:
dd bs=5000 seek=1if=/dev/null of=./H.txt
... que cria (ou trunca) um \0NULarquivo preenchido no diretório atual chamado H.txt com tamanho de 5000 bytes. ddprocura direto para o offset e preenche NUL por trás dele.
<&1 dd bs=5000 conv=sync,noerror count=1| tr \\0 H >./H.txt
... que cria um arquivo com o mesmo nome e tamanho, mas preenchido com caracteres H / H. Ele aproveita ddo comportamento spec'd de escrever pelo menos um nulo-quarteirão inteiro em caso de um erro de leitura quando noerrore syncconversões são especificados (e - sem count=- provavelmente continuar mais tempo do que você poderia querer) , e intencionalmente redirecionamentos um descritor de arquivo writeonly no ddstdin.
Os %.0smeios para converter o argumento como uma string , com uma precisão de zero. De acordo com man 3 printf, o valor de precisão nesse caso fornece
[...] the maximum number of characters to be printed from a
string for s and S conversions.
portanto, quando a precisão é zero, o argumento da string não é impresso. No entanto, o H(que faz parte do especificador de formato) é impresso quantas vezes houver argumentos, pois de acordo com a printfseçãoman bash
The format is reused as necessary to consume all of the argu‐
ments.If the format requires more arguments than are supplied,
the extra format specifications behave as if a zero value or
null string, as appropriate, had been supplied.
Nesse caso, %.0ssempre imprime uma instância do (s) caractere (s) que o precede, H neste caso. Quando você usa {1..5000}, o shell o expande e se torna:
printf 'H%.0s'1234...5000> H.txt
ou seja, o comando printf agora tem 5000 argumentos e, para cada argumento, você receberá um H. Estes não precisam ser seqüenciais ou numéricos:
printf 'H%.0s' a bc fg 1234
imprime HHHHH- ou seja, o número de argumentos, 5 neste caso.
Observe que as elipses no 1º exemplo acima não são inseridas literalmente, elas estão lá para indicar uma sequência ou intervalo.
tcsh
ouzsh
,repeat 5000 printf H
é mais fácil de entender. Comperl
:print "H" x 5000
(note que esse{1..5000}
é um operador zsh inspirado porperl
's1..5000
um e depois copiado por ksh93 e bash)yes H|head -5000|tr -d '\012'
dd if=/dev/zero bs=5000 count=1 | tr '\0' H
yes H| head -n 2500| tr \\n H
Respostas:
Esse comando depende do shell gerar 5000 argumentos e passá-los aos
printf
quais os ignora. Embora possa parecer bastante rápido - e seja relativo a algumas coisas - o shell ainda deve gerar todas essas strings como args (e delimitá-las) e assim por diante.Além do fato de que os Hs gerados não podem ser impressos até que o shell itere primeiro para 5000, esse comando também custa na memória tudo o que é necessário para armazenar e delimitar os argumentos de sequência numérica para
printf
somar os Hs. Da mesma maneira que você pode:... que gera uma sequência de 5.000 espaços - que, pelo menos, geralmente são apenas um byte e não custam nada para delimitar porque não são delimitados. Alguns testes indicam que, mesmo com apenas 5000 bytes, o custo do garfo e do tubo necessário
tr
vale a pena mesmo nesse caso, e quase sempre ocorre quando os números aumentam.Eu corri...
...e...
Cada uma cerca de 5 vezes por peça (nada de científico aqui - apenas anedótico) e a versão de expansão da cinta
tr
tiveram em média um pouco mais de 0,02 segundos no tempo total de processamento, mas a versão chegou em média 0,012 segundos no total - e atr
versão foi melhorada toda vez. Não posso dizer que estou surpreso -{brace expansion}
é um recurso de taquigrafia interativo útil do shell, mas geralmente é uma coisa muito esbanjadora para se fazer em qualquer tipo de script. A forma comum:... quando você pensa sobre isso, são realmente dois
for
loops - o primeiro é interno e está implícito, pois o shell deve fazer um loop de alguma maneira para gerar esses iteradores antes de salvá-los e iterá-los novamente para o seufor
loop. Geralmente, essas coisas são feitas melhor como:... porque você armazena apenas muito poucos valores e os substitui à medida que avança, além de fazer a iteração enquanto gera os iteráveis.
De qualquer forma, como o preenchimento de espaço mencionado anteriormente, você também pode usar
printf
para zeropar um número arbitrário de dígitos, é claro, como:Faço as duas coisas sem argumentos, porque para cada argumento especificado na
printf
string de formato de um argumento, quando não é encontrado, a string nula é usada - que é interpretada como zero para um argumento de dígito ou vazia para uma string.Esse é o outro lado (e - na minha opinião - mais eficiente) da moeda quando comparado com o comando da pergunta - embora seja possível não obter nada de algo como você faz ao
printf %.0
estender as seqüências de caracteres para cada argumento, também é é possível obter algo do nada.Ainda mais rápido para grandes quantidades de bytes gerados, você pode usar
dd
como:... e
dd
oseek=[num]
argumento de arquivos regulares pode ser usado para maior vantagem. Você pode obter novas linhas de 64k em vez de nulas se adicionar as opções,unblock cbs=1
acima e a partir daí poderá injetar seqüências arbitrárias por linha compaste
e/dev/null
- mas nesse caso, se estiver disponível, você também poderá usar:Aqui estão mais alguns
dd
exemplos de qualquer maneira:... que cria (ou trunca) um
\0NUL
arquivo preenchido no diretório atual chamado H.txt com tamanho de 5000 bytes.dd
procura direto para o offset e preenche NUL por trás dele.... que cria um arquivo com o mesmo nome e tamanho, mas preenchido com caracteres H / H. Ele aproveita
dd
o comportamento spec'd de escrever pelo menos um nulo-quarteirão inteiro em caso de um erro de leitura quandonoerror
esync
conversões são especificados (e - semcount=
- provavelmente continuar mais tempo do que você poderia querer) , e intencionalmente redirecionamentos um descritor de arquivo writeonly nodd
stdin.fonte
Os
%.0s
meios para converter o argumento como uma string , com uma precisão de zero. De acordo comman 3 printf
, o valor de precisão nesse caso forneceportanto, quando a precisão é zero, o argumento da string não é impresso. No entanto, o
H
(que faz parte do especificador de formato) é impresso quantas vezes houver argumentos, pois de acordo com aprintf
seçãoman bash
fonte
Nesse caso,
%.0s
sempre imprime uma instância do (s) caractere (s) que o precede, H neste caso. Quando você usa {1..5000}, o shell o expande e se torna:ou seja, o comando printf agora tem 5000 argumentos e, para cada argumento, você receberá um H. Estes não precisam ser seqüenciais ou numéricos:
imprime
HHHHH
- ou seja, o número de argumentos, 5 neste caso.Observe que as elipses no 1º exemplo acima não são inseridas literalmente, elas estão lá para indicar uma sequência ou intervalo.
fonte