Como eu poderia fazer isso echo?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'oupython -c 'print "=" * 100'
printfcom seq)svrb=`printf '%.sv' $(seq $vrb)`
Como eu poderia fazer isso echo?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'oupython -c 'print "=" * 100'
printfcom seq)svrb=`printf '%.sv' $(seq $vrb)`
Respostas:
Você pode usar:
printf '=%.0s' {1..100}
Como isso funciona:
O Bash se expande {1..100} para que o comando se torne:
printf '=%.0s' 1 2 3 4 ... 100
Eu configurei o formato printf para o =%.0sque significa que ele sempre imprimirá um único, =independentemente do argumento que for fornecido. Portanto, imprime 100 =s.
repl = 100, por exemplo ( evalé exigido truques, infelizmente, para basear a expansão cinta em uma variável):repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
seqpor exemplo, por exemplo $(seq 1 $limit).
$s%.0spara %.0s$shífen, causando um printferro.
printf: ele continua a aplicar a string de formato até que não haja mais argumentos. Eu tinha assumido que processou a string de formato apenas uma vez!
Não é fácil. Mas por exemplo:
seq -s= 100|tr -d '[:digit:]'
Ou talvez uma maneira de conformidade padrão:
printf %100s |tr " " "="
Há também um tput rep, mas quanto aos meus terminais em mãos (xterm e linux), eles não parecem suportá-lo :)
=caracteres.
printf tré a única solução POSIX porque seq, yese {1..3}não é POSIX.
printf %100s | sed 's/ /abc/g'- gera 'abcabcabc ...'
tr). Você também pode estendê-lo a algo como printf "%${COLUMNS}s\n" | tr " " "=".
wc. A única conclusão que posso tirar disso é " seqnão deve ser usada".
Ponta do chapéu para @ gniourf_gniourf por sua contribuição.
Nota: Esta resposta não responde à pergunta original, mas complementa as respostas úteis existentes comparando o desempenho .
As soluções são comparadas apenas em termos de velocidade de execução - os requisitos de memória não são levados em consideração (eles variam entre as soluções e podem importar com grandes contagens de repetição).
Resumo:
${var// /=}), pois é proibitivamente lento.A seguir, são mostrados os tempos do iMac de final de 2012 com uma CPU Intel Core i5 de 3,2 GHz e uma unidade Fusion, executando o OSX 10.10.4 e o bash 3.2.57, e são a média de 1000 execuções.
As entradas são:
M... uma solução potencialmente com vários caracteresS... uma solução única para caracteresP ... uma solução compatível com POSIX[M, P] printf %.s= [dogbane]: 0.0002
[M ] printf + bash global substr. replacement [Tim]: 0.0005
[M ] echo -n - brace expansion loop [eugene y]: 0.0007
[M ] echo -n - arithmetic loop [Eliah Kagan]: 0.0013
[M ] seq -f [Sam Salisbury]: 0.0016
[M ] jot -b [Stefan Ludwig]: 0.0016
[M ] awk - $(count+1)="=" [Steven Penny (variant)]: 0.0019
[M, P] awk - while loop [Steven Penny]: 0.0019
[S ] printf + tr [user332325]: 0.0021
[S ] head + tr [eugene y]: 0.0021
[S, P] dd + tr [mklement0]: 0.0021
[M ] printf + sed [user332325 (comment)]: 0.0021
[M ] mawk - $(count+1)="=" [Steven Penny (variant)]: 0.0025
[M, P] mawk - while loop [Steven Penny]: 0.0026
[M ] gawk - $(count+1)="=" [Steven Penny (variant)]: 0.0028
[M, P] gawk - while loop [Steven Penny]: 0.0028
[M ] yes + head + tr [Digital Trauma]: 0.0029
[M ] Perl [sid_com]: 0.0059
awke perlsoluções.[M ] Perl [sid_com]: 0.0067
[M ] mawk - $(count+1)="=" [Steven Penny (variant)]: 0.0254
[M ] gawk - $(count+1)="=" [Steven Penny (variant)]: 0.0599
[S ] head + tr [eugene y]: 0.1143
[S, P] dd + tr [mklement0]: 0.1144
[S ] printf + tr [user332325]: 0.1164
[M, P] mawk - while loop [Steven Penny]: 0.1434
[M ] seq -f [Sam Salisbury]: 0.1452
[M ] jot -b [Stefan Ludwig]: 0.1690
[M ] printf + sed [user332325 (comment)]: 0.1735
[M ] yes + head + tr [Digital Trauma]: 0.1883
[M, P] gawk - while loop [Steven Penny]: 0.2493
[M ] awk - $(count+1)="=" [Steven Penny (variant)]: 0.2614
[M, P] awk - while loop [Steven Penny]: 0.3211
[M, P] printf %.s= [dogbane]: 2.4565
[M ] echo -n - brace expansion loop [eugene y]: 7.5877
[M ] echo -n - arithmetic loop [Eliah Kagan]: 13.5426
[M ] printf + bash global substr. replacement [Tim]: n/a
${foo// /=}) do Bash é inexplicavelmente dolorosamente lenta com strings grandes e foi tirada da corrida (demorou cerca de 50 minutos (!) No Bash 4.3.30 e ainda mais no Bash 3.2.57 - nunca esperei para terminar).(( i= 0; ... ))) são mais lentos que os com extensão de chaves ( {1..n}) - embora os loops aritméticos sejam mais eficientes em termos de memória.awkrefere-se ao BSD awk (como também encontrado no OSX) - é visivelmente mais lento que o gawk(GNU Awk) e especialmente mawk.Aqui está o script Bash ( testrepeat) que produziu o acima. São necessários 2 argumentos:
Em outras palavras: os tempos acima foram obtidos com testrepeat 100 1000etestrepeat 1000000 1000
#!/usr/bin/env bash
title() { printf '%s:\t' "$1"; }
TIMEFORMAT=$'%6Rs'
# The number of repetitions of the input chars. to produce
COUNT_REPETITIONS=${1?Arguments: <charRepeatCount> [<testRunCount>]}
# The number of test runs to perform to derive the average timing from.
COUNT_RUNS=${2:-1}
# Discard the (stdout) output generated by default.
# If you want to check the results, replace '/dev/null' on the following
# line with a prefix path to which a running index starting with 1 will
# be appended for each test run; e.g., outFilePrefix='outfile', which
# will produce outfile1, outfile2, ...
outFilePrefix=/dev/null
{
outFile=$outFilePrefix
ndx=0
title '[M, P] printf %.s= [dogbane]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
# !! In order to use brace expansion with a variable, we must use `eval`.
eval "
time for (( n = 0; n < COUNT_RUNS; n++ )); do
printf '%.s=' {1..$COUNT_REPETITIONS} >"$outFile"
done"
title '[M ] echo -n - arithmetic loop [Eliah Kagan]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
for ((i=0; i<COUNT_REPETITIONS; ++i)); do echo -n =; done >"$outFile"
done
title '[M ] echo -n - brace expansion loop [eugene y]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
# !! In order to use brace expansion with a variable, we must use `eval`.
eval "
time for (( n = 0; n < COUNT_RUNS; n++ )); do
for i in {1..$COUNT_REPETITIONS}; do echo -n =; done >"$outFile"
done
"
title '[M ] printf + sed [user332325 (comment)]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
printf "%${COUNT_REPETITIONS}s" | sed 's/ /=/g' >"$outFile"
done
title '[S ] printf + tr [user332325]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
printf "%${COUNT_REPETITIONS}s" | tr ' ' '=' >"$outFile"
done
title '[S ] head + tr [eugene y]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
head -c $COUNT_REPETITIONS < /dev/zero | tr '\0' '=' >"$outFile"
done
title '[M ] seq -f [Sam Salisbury]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
seq -f '=' -s '' $COUNT_REPETITIONS >"$outFile"
done
title '[M ] jot -b [Stefan Ludwig]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
jot -s '' -b '=' $COUNT_REPETITIONS >"$outFile"
done
title '[M ] yes + head + tr [Digital Trauma]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
yes = | head -$COUNT_REPETITIONS | tr -d '\n' >"$outFile"
done
title '[M ] Perl [sid_com]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
perl -e "print \"=\" x $COUNT_REPETITIONS" >"$outFile"
done
title '[S, P] dd + tr [mklement0]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
dd if=/dev/zero bs=$COUNT_REPETITIONS count=1 2>/dev/null | tr '\0' "=" >"$outFile"
done
# !! On OSX, awk is BSD awk, and mawk and gawk were installed later.
# !! On Linux systems, awk may refer to either mawk or gawk.
for awkBin in awk mawk gawk; do
if [[ -x $(command -v $awkBin) ]]; then
title "[M ] $awkBin"' - $(count+1)="=" [Steven Penny (variant)]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
$awkBin -v count=$COUNT_REPETITIONS 'BEGIN { OFS="="; $(count+1)=""; print }' >"$outFile"
done
title "[M, P] $awkBin"' - while loop [Steven Penny]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
time for (( n = 0; n < COUNT_RUNS; n++ )); do
$awkBin -v count=$COUNT_REPETITIONS 'BEGIN { while (i++ < count) printf "=" }' >"$outFile"
done
fi
done
title '[M ] printf + bash global substr. replacement [Tim]'
[[ $outFile != '/dev/null' ]] && outFile="$outFilePrefix$((++ndx))"
# !! In Bash 4.3.30 a single run with repeat count of 1 million took almost
# !! 50 *minutes*(!) to complete; n Bash 3.2.57 it's seemingly even slower -
# !! didn't wait for it to finish.
# !! Thus, this test is skipped for counts that are likely to be much slower
# !! than the other tests.
skip=0
[[ $BASH_VERSINFO -le 3 && COUNT_REPETITIONS -gt 1000 ]] && skip=1
[[ $BASH_VERSINFO -eq 4 && COUNT_REPETITIONS -gt 10000 ]] && skip=1
if (( skip )); then
echo 'n/a' >&2
else
time for (( n = 0; n < COUNT_RUNS; n++ )); do
{ printf -v t "%${COUNT_REPETITIONS}s" '='; printf %s "${t// /=}"; } >"$outFile"
done
fi
} 2>&1 |
sort -t$'\t' -k2,2n |
awk -F $'\t' -v count=$COUNT_RUNS '{
printf "%s\t", $1;
if ($2 ~ "^n/a") { print $2 } else { printf "%.4f\n", $2 / count }}' |
column -s$'\t' -t
In order to use brace expansion with a variable, we must use `eval`Py
Há mais de uma maneira de fazer isso.
Usando um loop:
A expansão entre chaves pode ser usada com literais inteiros:
for i in {1..100}; do echo -n =; done Um loop tipo C permite o uso de variáveis:
start=1
end=100
for ((i=$start; i<=$end; i++)); do echo -n =; done
Usando o printfbuiltin:
printf '=%.0s' {1..100}
A especificação de uma precisão aqui trunca a string para caber na largura especificada ( 0). Como printfreutiliza a string de formato para consumir todos os argumentos, isso simplesmente imprime "="100 vezes.
Usando head( printf, etc) e tr:
head -c 100 < /dev/zero | tr '\0' '='
printf %100s | tr " " "="
head/ tr, que funciona bem mesmo com altas contagens de repetição (ressalva pequena: head -cnão é compatível com POSIX, mas o BSD e o GNU o headimplementam); embora as outras duas soluções sejam lentas nesse caso, elas também têm a vantagem de trabalhar com seqüências de vários caracteres.
yese head- útil se você quiser um certo número de novas linhas: yes "" | head -n 100. trpode fazê-lo imprimir qualquer caractere:yes "" | head -n 100 | tr "\n" "="; echo
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/nullé significativamente mais lento que a head -c100000000 < /dev/zero | tr '\0' '=' >/dev/nullversão. Claro que você precisa usar um tamanho de bloco de 100M + para medir a diferença de tempo razoavelmente. 100M bytes levam 1,7 se 1 s com as duas versões respectivas mostradas. Tirei o tr e apenas o joguei /dev/nulle obtive 0,287 s para a headversão e 0,675 s para a ddversão por um bilhão de bytes.
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null=> 0,21332 s, 469 MB/s; Para: dd if=/dev/zero count=100 bs=1000000| tr '\0' '=' >/dev/null=> 0,161579 s, 619 MB/s;
Acabei de encontrar uma maneira muito fácil de fazer isso usando seq:
UPDATE: Funciona no BSD seqque acompanha o OS X. YMMV com outras versões
seq -f "#" -s '' 10
Imprimirá '#' 10 vezes, assim:
##########
-f "#"define a string de formato para ignorar os números e apenas imprimir #para cada um.-s '' define o separador como uma sequência vazia para remover as novas linhas que seq insere entre cada número-fe -sparecem ser importantes.EDIT: Aqui está em uma função útil ...
repeat () {
seq -f $1 -s '' $2; echo
}
Que você pode chamar assim ...
repeat "#" 10
NOTA: Se você estiver repetindo #, as aspas são importantes!
seq: format ‘#’ has no % directive. seqé para números, não para strings. Veja gnu.org/software/coreutils/manual/html_node/seq-invocation.html
seqestá sendo reutilizado de maneira inteligente aqui para replicar as strings : a string de formato passada para -f- normalmente usada para formatar os números que estão sendo gerados - contém apenas a string a ser replicada aqui, para que a saída contenha apenas cópias dessa string. Infelizmente, o GNU seqinsiste na presença de um formato numérico na string de formato, que é o erro que você está vendo.
"$1"(aspas duplas), para que você também possa passar caracteres como '*'e strings com espaço em branco incorporado. Finalmente, se você quiser poder usá- %lo, precisará dobrá- lo (caso contrário, seqvocê achará que faz parte de uma especificação de formato como %f); usando "${1//%/%%}"iria cuidar disso. Como (como você mencionou) você está usando o BSD seq , isso funcionará em sistemas operacionais semelhantes ao BSD em geral (por exemplo, FreeBSD) - por outro lado, não funcionará no Linux , onde o GNU seq é usado.
Aqui estão duas maneiras interessantes:
ubuntu @ ubuntu: ~ $ yes = | cabeça -10 | colar -s -d '' - ========== ubuntu @ ubuntu: ~ $ yes = | cabeça -10 | tr-d "\ n" ========== ubuntu @ ubuntu: ~ $
Observe que esses dois são sutilmente diferentes - O pastemétodo termina em uma nova linha. O trmétodo não.
paste inexplicavelmente requer -d '\0'a especificação de um delimitador vazio e falha com -d ''- -d '\0'deve funcionar com todas as pasteimplementações compatíveis com POSIX e de fato também funciona com o GNU paste .
yes | mapfile -n 100 -C 'printf = \#' -c 1
time yes = | head -500 | paste -s -d '\0' -; time yes | mapfile -n 500 -C 'printf = \#' -c 1. Mais importante, porém: se você estiver usando printfqualquer maneira, assim como você pode ir com a abordagem mais simples e mais eficiente da resposta aceita:printf '%.s=' $(seq 500)
Não existe uma maneira simples. Evite loops usando printfe substituindo.
str=$(printf "%40s")
echo ${str// /rep}
# echoes "rep" 40 times.
repl = 100, por exemplo (não emite um à direita \n):repl() { local ts=$(printf "%${2}s"); printf %s "${ts// /$1}"; }
Se você deseja conformidade e consistência POSIX em diferentes implementações de echoe printf, e / ou shells, além de bash:
seq(){ n=$1; while [ $n -le $2 ]; do echo $n; n=$((n+1)); done ;} # If you don't have it.
echo $(for each in $(seq 1 100); do printf "="; done)
... produzirá a mesma saída que perl -E 'say "=" x 100'praticamente em qualquer lugar.
seqnão é um utilitário POSIX (embora os sistemas BSD e Linux tenham implementações dele) - você pode fazer a aritmética do shell POSIX com um whileloop, como na resposta do @ Xennex81 (com printf "=", como você sugere corretamente, em vez de echo -n).
calé POSIX. seqnão é. De qualquer forma, em vez de reescrever a resposta com um loop while (como você diz, isso já está em outras respostas), adicionarei uma função RYO. Mais educativo assim ;-).
A pergunta era sobre como fazer isso com echo:
echo -e ''$_{1..100}'\b='
Isso fará exatamente o mesmo que perl -E 'say "=" x 100'com echoapenas.
Uma maneira pura do Bash sem eval, sem subcascas, sem ferramentas externas, sem expansões de chaves (ou seja, você pode ter o número para repetir em uma variável):
Se você receber uma variável nque se expande para um número (não negativo) e uma variável pattern, por exemplo,
$ n=5
$ pattern=hello
$ printf -v output '%*s' "$n"
$ output=${output// /$pattern}
$ echo "$output"
hellohellohellohellohello
Você pode fazer uma função com isso:
repeat() {
# $1=number of patterns to repeat
# $2=pattern
# $3=output variable name
local tmp
printf -v tmp '%*s' "$1"
printf -v "$3" '%s' "${tmp// /$2}"
}
Com este conjunto:
$ repeat 5 hello output
$ echo "$output"
hellohellohellohellohello
Para este pequeno truque, estamos usando printfbastante:
-v varname: em vez de imprimir na saída padrão, printfcolocará o conteúdo da sequência formatada em variável varname.printfusará o argumento para imprimir o número correspondente de espaços. Por exemplo, printf '%*s' 42imprimirá 42 espaços.${var// /$pattern}expandiremos para a expansão de varcom todos os espaços substituídos pela expansão de $pattern.Você também pode se livrar da tmpvariável na repeatfunção usando expansão indireta:
repeat() {
# $1=number of patterns to repeat
# $2=pattern
# $3=output variable name
printf -v "$3" '%*s' "$1"
printf -v "$3" '%s' "${!3// /$2}"
}
bashas operações globais de substituição de cadeia de caracteres no contexto da expansão de parâmetros ( ${var//old/new}) são particularmente lentas: extremamente lenta no bash 3.2.57e lenta no bash 4.3.30, pelo menos no meu sistema OSX 10.10.3 em uma máquina Intel Core i5 de 3,2 Ghz: com uma contagem de 1.000, as coisas são lentas ( 3.2.57) / rápidas ( 4.3.30): 0.1 / 0.004 segundos. Aumentar a contagem para 10.000 gera números surpreendentemente diferentes: repeat 10000 = varleva cerca de 80 segundos (!) No bash 3.2.57e cerca de 0,3 segundos no bash 4.3.30(muito mais rápido que no 3.2.57, mas ainda lento).
#!/usr/bin/awk -f
BEGIN {
OFS = "="
NF = 100
print
}
Ou
#!/usr/bin/awk -f
BEGIN {
while (z++ < 100) printf "="
}
awk 'BEGIN { while (c++ < 100) printf "=" }'. Envolto em uma função parametrizada concha (invocação como repeat 100 =, por exemplo): repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { txt=substr(txt, 2); while (i++ < count) printf txt }'; }. (O manequim .prefixo caractere e complementar substrchamada são necessários para o trabalho em torno de um bug no BSD awk, onde passando um valor variável que começa com =quebras de comando.)
NF = 100solução é muito inteligente (apesar de obter 100 =, você deve usar NF = 101). As advertências são de que ele trava BSD awk(mas é muito rápido com gawke até mesmo mais rápido com mawk), e que discute POSIX nem atribuir a NF, nem o uso de campos em BEGINblocos. Você pode fazê-lo funcionar no BSD awktambém com um pequeno ajuste: awk 'BEGIN { OFS = "="; $101=""; print }'(mas curiosamente, no BSD awkque não é mais rápido que a solução de loop). Como uma solução de shell parametrizado: repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { OFS=substr(txt, 2); $(count+1)=""; print }'; }.
original-awké o nome no Linux do awk mais antigo, semelhante ao awk do BSD, que também foi relatado como travado, se você quiser tentar isso. Observe que travar é geralmente o primeiro passo para encontrar um bug explorável. Esta resposta está promovendo códigos inseguros.
original-awknão é padrão e não é recomendado #
awk NF=100 OFS='=' <<< ""(using bashand gawk) #
Eu acho que o objetivo original da pergunta era fazer isso apenas com os comandos internos do shell. Então, forloops e printfs seria legítimo, enquanto rep, perle também jotabaixo não faria. Ainda assim, o seguinte comando
jot -s "/" -b "\\" $((COLUMNS/2))
por exemplo, imprime uma linha de janelas inteira \/\/\/\/\/\/\/\/\/\/\/\/
jot -s '' -b '=' 100. A ressalva é que, embora as plataformas semelhantes a BSD, incluindo OSX, venham jot, as distribuições Linux não .
apt install athena-jotseria fornecido jot.
Como outros já disseram, na expansão do bash brace precede a expansão do parâmetro , portanto, os intervalos podem conter apenas literais. e forneça soluções limpas, mas não totalmente portáteis de um sistema para outro, mesmo se você estiver usando o mesmo shell em cada um. (Embora esteja cada vez mais disponível; por exemplo, no FreeBSD 9.3 e superior .) E outras formas de indireção sempre funcionam, mas são um tanto deselegantes.{m,n}seqjotseqeval
Felizmente, o bash suporta o estilo C para loops (apenas com expressões aritméticas). Então, aqui está uma maneira concisa de "pure bash":
repecho() { for ((i=0; i<$1; ++i)); do echo -n "$2"; done; echo; }
Isso leva o número de repetições como o primeiro argumento e a sequência a ser repetida (que pode ser um caractere único, como na descrição do problema) como o segundo argumento. repecho 7 bsaídas bbbbbbb(terminadas por uma nova linha).
Dennis Williamson deu essencialmente essa solução há quatro anos em sua excelente resposta para Criando sequência de caracteres repetidos no shell script . Meu corpo da função difere um pouco do código lá:
Como o foco aqui é repetir um único caractere e o shell é bash, provavelmente é seguro usá-lo em echovez de printf. E li a descrição do problema nesta pergunta como expressando uma preferência para imprimir echo. A definição da função acima funciona no bash e no ksh93 . Embora printfseja mais portátil (e geralmente deva ser usado para esse tipo de coisa), echoa sintaxe é indiscutivelmente mais legível.
Os echocomponentes de alguns shells interpretam -por si só como uma opção - mesmo que o significado usual de -, usar stdin para entrada, seja sem sentido echo. O zsh faz isso. E definitivamente existem echos que não reconhecem -n, pois isso não é padrão . (Muitas conchas no estilo Bourne não aceitam o estilo C para loops, portanto, seu echocomportamento não precisa ser considerado ..)
Aqui, a tarefa é imprimir a sequência; lá , era para atribuí-lo a uma variável.
Se $né o número desejado de repetições e você não precisa reutilizá-lo, e deseja algo ainda mais curto:
while ((n--)); do echo -n "$s"; done; echo
ndeve ser uma variável - dessa maneira não funciona com parâmetros posicionais. $sé o texto a ser repetido.
printf "%100s" | tr ' ' '='é ótimo.
zsh, aliás. A abordagem echo-in-a-loop funciona bem para contagens menores de repetição, mas para as maiores existem alternativas compatíveis com POSIX baseadas em utilitários , conforme evidenciado pelo comentário do @ Slomojo.
(while ((n--)); do echo -n "$s"; done; echo)
echosuporte interno -n. O espírito do que você está dizendo é absolutamente correto. printfquase sempre deve ser preferido echo, pelo menos em uso não interativo. Mas não acho que seja inapropriado ou enganoso dar uma echoresposta a uma pergunta que pediu uma e que forneceu informações suficientes para saber que funcionaria . Observe também que o suporte para ((n--))(sem a $) não é garantido pelo POSIX.
Python é onipresente e funciona da mesma maneira em todos os lugares.
python -c "import sys; print('*' * int(sys.argv[1]))" "=" 100
Caractere e contagem são passados como parâmetros separados.
python -c "import sys; print(sys.argv[1] * int(sys.argv[2]))" "=" 100
Outra forma de repetir uma sequência arbitrária n vezes:
Prós:
Contras:
yescomando do Gnu Core Utils .#!/usr/bin/sh
to_repeat='='
repeat_count=80
yes "$to_repeat" | tr -d '\n' | head -c "$repeat_count"
Com um terminal ANSI e caracteres US-ASCII para repetir. Você pode usar uma sequência de escape ANSI CSI. É a maneira mais rápida de repetir um personagem.
#!/usr/bin/env bash
char='='
repeat_count=80
printf '%c\e[%db' "$char" "$repeat_count"
Ou estaticamente:
Imprima uma linha de 80 vezes =:
printf '=\e[80b\n'
Limitações:
repeat_charsequência ANSI CSI.repeat_charsequência ANSI CSI no caractere repetido.Aqui está o que eu uso para imprimir uma linha de caracteres na tela no Linux (com base na largura do terminal / tela)
printf '=%.0s' $(seq 1 $(tput cols))
Explicação:
Imprima um sinal de igual quantas vezes a sequência fornecida:
printf '=%.0s' #sequence
Use a saída de um comando (esse é um recurso do bash chamado Substituição de Comando):
$(example_command)
Dê uma sequência, usei 1 a 20 como exemplo. No comando final, o comando tput é usado em vez de 20:
seq 1 20
Forneça o número de colunas atualmente usadas no terminal:
tput cols
for i in {1..100}
do
echo -n '='
done
echo
O mais simples é usar esta linha em csh / tcsh:
printf "%50s\n" '' | tr '[:blank:]' '[=]'
Uma alternativa mais elegante à solução Python proposta poderia ser:
python -c 'print "="*(1000)'
Caso deseje repetir um caractere n vezes, sendo um número VARIÁVEL de vezes, dependendo, digamos, do comprimento de uma string que você possa fazer:
#!/bin/bash
vari='AB'
n=$(expr 10 - length $vari)
echo 'vari equals.............................: '$vari
echo 'Up to 10 positions I must fill with.....: '$n' equal signs'
echo $vari$(perl -E 'say "=" x '$n)
Exibe:
vari equals.............................: AB
Up to 10 positions I must fill with.....: 8 equal signs
AB========
lengthnão vai funcionar expr, você provavelmente quis dizer n=$(expr 10 - ${#vari}); no entanto, é mais simples e mais eficiente usar a expansão aritmética do Bash: n=$(( 10 - ${#vari} )). Além disso, no centro da sua resposta está a própria abordagem Perl para a qual o OP está procurando uma alternativa do Bash .
Esta é a versão mais longa do que Eliah Kagan estava defendendo:
while [ $(( i-- )) -gt 0 ]; do echo -n " "; done
Claro que você também pode usar o printf para isso, mas não do meu jeito:
printf "%$(( i*2 ))s"
Esta versão é compatível com Dash:
until [ $(( i=i-1 )) -lt 0 ]; do echo -n " "; done
sendo eu o número inicial.
function repeatString()
{
local -r string="${1}"
local -r numberToRepeat="${2}"
if [[ "${string}" != '' && "${numberToRepeat}" =~ ^[1-9][0-9]*$ ]]
then
local -r result="$(printf "%${numberToRepeat}s")"
echo -e "${result// /${string}}"
fi
}
Execuções de amostra
$ repeatString 'a1' 10
a1a1a1a1a1a1a1a1a1a1
$ repeatString 'a1' 0
$ repeatString '' 10
Referência lib em: https://github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash
Minha resposta é um pouco mais complicada e, provavelmente, não é perfeita, mas para aqueles que desejam gerar grandes números, consegui fazer cerca de 10 milhões em 3 segundos.
repeatString(){
# argument 1: The string to print
# argument 2: The number of times to print
stringToPrint=$1
length=$2
# Find the largest integer value of x in 2^x=(number of times to repeat) using logarithms
power=`echo "l(${length})/l(2)" | bc -l`
power=`echo "scale=0; ${power}/1" | bc`
# Get the difference between the length and 2^x
diff=`echo "${length} - 2^${power}" | bc`
# Double the string length to the power of x
for i in `seq "${power}"`; do
stringToPrint="${stringToPrint}${stringToPrint}"
done
#Since we know that the string is now at least bigger than half the total, grab however many more we need and add it to the string.
stringToPrint="${stringToPrint}${stringToPrint:0:${diff}}"
echo ${stringToPrint}
}
O mais simples é usar este one-liner no bash:
seq 10 | xargs -n 1 | xargs -I {} echo -n ===\>;echo
A maioria das soluções existentes depende do {1..10}suporte à sintaxe do shell, que é bash- e zsh- específico, e não funciona no tcshOpenBSD kshe na maioria dos não-bash sh.
O seguinte deve funcionar no OS X e em todos os sistemas * BSD em qualquer shell; de fato, ele pode ser usado para gerar uma matriz inteira de vários tipos de espaço decorativo:
$ printf '=%.0s' `jot 64` | fold -16
================
================
================
================$
Infelizmente, não temos uma nova linha à direita; que pode ser corrigido com um extra printf '\n'após a dobra:
$ printf "=%.0s" `jot 64` | fold -16 ; printf "\n"
================
================
================
================
$
Referências:
Minha proposta (aceitando valores variáveis para n):
n=100
seq 1 $n | xargs -I {} printf =