for sh in bash zsh yash dash mksh ksh
do printf "\n%s:\t" "$sh"
time "$sh" -c '
str="some string"
set "" ""
while ${20001+"break"}
do set "$@$@";done
IFS=A; printf %.100000s\n "$str$*$*$*$*$*"'|
wc -c
done
bash: 100001
"$sh" -c 0.15s user 0.01s system 94% cpu 0.176 total
wc -c 0.00s user 0.00s system 1% cpu 0.175 total
zsh: 100001
"$sh" -c 0.03s user 0.01s system 97% cpu 0.034 total
wc -c 0.00s user 0.00s system 9% cpu 0.034 total
yash: 100001
"$sh" -c 0.06s user 0.01s system 94% cpu 0.067 total
wc -c 0.00s user 0.00s system 5% cpu 0.067 total
dash: 100001
"$sh" -c 0.02s user 0.01s system 92% cpu 0.029 total
wc -c 0.00s user 0.00s system 11% cpu 0.028 total
ksh: 100001
"$sh" -c 0.02s user 0.00s system 96% cpu 0.021 total
wc -c 0.00s user 0.00s system 16% cpu 0.021 total
Portanto, isso compensa os vários shells configurados como $sh
no loop for
na rapidez com que eles podem gerar uma string de 100.000 caracteres. Os primeiros 11 desses 100.000 caracteres são some string
como primeiro definido para o valor de $str
, mas o preenchimento final é de 999.989 A
caracteres.
Os shells obtêm os caracteres A
em $*
, que substitui o primeiro caractere no valor do parâmetro especial do shell $IFS
como um delimitador de concatenação entre cada parâmetro posicional no argumento do shell array. Como todos os argumentos são ""
null, os únicos caracteres em $*
são os caracteres delimitadores.
Os argumentos são acumulados em uma taxa exponencial para cada iteração do loop while
- que somente break
s quando o parâmetro $20001
foi finalmente ${set+}
. Até lá, basicamente o loop while
faz:
### first iteration
while $unset_param; do set "" """" ""; done
### second iteration
while $unset_param; do set "" "" """" "" ""; done
### third iteration
while $unset_param; do set "" "" "" "" """" "" "" "" ""; done
... e assim por diante.
Após o loop while
concluir o $IFS
ser definido como A
, o parâmetro especial do shell $*
será concatenado cinco vezes para a final de $str
. printf
reduz o argumento %s
tring resultante para um máximo de .100000
bytes antes de gravá-lo no stdout.
Pode-se usar a mesma estratégia como:
str='some string'
set "" ""
while ${51+"break"}; do set "$@$@"; done
shift "$((${#}-(51-${#str}))"
... o que resulta em uma contagem total de argumentos de 40 - e, portanto, 39 delimitadores ...
IFS=.; printf %s\n "$str$*"
some string.......................................
E você pode reutilizar os mesmos argumentos que já definiu com um% diferente% co_de para um preenchimento diferente:
for IFS in a b c; do printf %s\n "$str$*"; done
some stringaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
some stringbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
some stringccccccccccccccccccccccccccccccccccccccc
Você também pode preencher os argumentos nulos com uma string de formato $IFS
em vez de usar printf
:
printf "%s m%sy%1ss%st%sr%si%sn%sg" "$str$@"
some string my string my string my string my string my string