Como eu poderia fazer isso echo
?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'
oupython -c 'print "=" * 100'
printf
com 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'
printf
com 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 =%.0s
que 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))"}"); }
seq
por exemplo, por exemplo $(seq 1 $limit)
.
$s%.0s
para %.0s$s
hífen, causando um printf
erro.
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
, yes
e {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 é " seq
nã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
awk
e perl
soluçõ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.awk
refere-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 1000
etestrepeat 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 printf
builtin:
printf '=%.0s' {1..100}
A especificação de uma precisão aqui trunca a string para caber na largura especificada ( 0
). Como printf
reutiliza 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 -c
não é compatível com POSIX, mas o BSD e o GNU o head
implementam); 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.
yes
e head
- útil se você quiser um certo número de novas linhas: yes "" | head -n 100
. tr
pode 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/null
versã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/null
e obtive 0,287 s para a head
versão e 0,675 s para a dd
versã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 seq
que 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-f
e -s
parecem 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
seq
está 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 seq
insiste 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, seq
você 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 paste
método termina em uma nova linha. O tr
mé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 paste
implementaçõ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 printf
qualquer 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 printf
e 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 echo
e 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.
seq
nã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 while
loop, como na resposta do @ Xennex81 (com printf "="
, como você sugere corretamente, em vez de echo -n
).
cal
é POSIX. seq
nã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 echo
apenas.
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 n
que 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 printf
bastante:
-v varname
: em vez de imprimir na saída padrão, printf
colocará o conteúdo da sequência formatada em variável varname
.printf
usará o argumento para imprimir o número correspondente de espaços. Por exemplo, printf '%*s' 42
imprimirá 42 espaços.${var// /$pattern}
expandiremos para a expansão de var
com todos os espaços substituídos pela expansão de $pattern
.Você também pode se livrar da tmp
variável na repeat
funçã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}"
}
bash
as 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.57
e 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 = var
leva cerca de 80 segundos (!) No bash 3.2.57
e 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 substr
chamada 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 = 100
soluçã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 gawk
e até mesmo mais rápido com mawk
), e que discute POSIX nem atribuir a NF
, nem o uso de campos em BEGIN
blocos. Você pode fazê-lo funcionar no BSD awk
também com um pequeno ajuste: awk 'BEGIN { OFS = "="; $101=""; print }'
(mas curiosamente, no BSD awk
que 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-awk
não é padrão e não é recomendado #
awk NF=100 OFS='=' <<< ""
(using bash
and gawk
) #
Eu acho que o objetivo original da pergunta era fazer isso apenas com os comandos internos do shell. Então, for
loops e printf
s seria legítimo, enquanto rep
, perl
e também jot
abaixo 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-jot
seria 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}
seq
jot
seq
eval
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 b
saí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 echo
vez 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 printf
seja mais portátil (e geralmente deva ser usado para esse tipo de coisa), echo
a sintaxe é indiscutivelmente mais legível.
Os echo
componentes 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 echo
s 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 echo
comportamento 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
n
deve 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)
echo
suporte interno -n
. O espírito do que você está dizendo é absolutamente correto. printf
quase sempre deve ser preferido echo
, pelo menos em uso não interativo. Mas não acho que seja inapropriado ou enganoso dar uma echo
resposta 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:
yes
comando 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_char
sequência ANSI CSI.repeat_char
sequê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========
length
nã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 tcsh
OpenBSD ksh
e 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 =