¿Cómo podría hacer esto echo?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'opython -c 'print "=" * 100'
printfcon seq)svrb=`printf '%.sv' $(seq $vrb)`
¿Cómo podría hacer esto echo?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'opython -c 'print "=" * 100'
printfcon seq)svrb=`printf '%.sv' $(seq $vrb)`
Respuestas:
Puedes usar:
printf '=%.0s' {1..100}
Cómo funciona esto:
Bash expande {1..100} por lo que el comando se convierte en:
printf '=%.0s' 1 2 3 4 ... 100
He configurado el formato de printf, lo =%.0sque significa que siempre imprimirá uno =sin importar el argumento que se le dé. Por lo tanto, imprime 100 =s.
repl = 100, por ejemplo ( evalse requiere truco, desafortunadamente, para basar la expansión de repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
seqlugar, por ejemplo $(seq 1 $limit).
$s%.0spara %.0s$sque los guiones causen un printferror.
printf: continúa aplicando la cadena de formato hasta que no quedan argumentos. ¡Asumí que procesó la cadena de formato solo una vez!
No hay manera fácil. Pero por ejemplo:
seq -s= 100|tr -d '[:digit:]'
O tal vez una forma de conformidad estándar:
printf %100s |tr " " "="
También hay un tput rep, pero en cuanto a mis terminales disponibles (xterm y linux) no parecen admitirlo :)
=caracteres.
printf tres la única solución POSIX porque seq, yesy {1..3}no son POSIX.
printf %100s | sed 's/ /abc/g'- genera 'abcabcabc ...'
tr). También podría extenderlo a algo así printf "%${COLUMNS}s\n" | tr " " "=".
wc. La única conclusión que puedo sacar de esto es " seqno se debe usar".
Punta del sombrero a @ gniourf_gniourf por su aporte.
Nota: Esta respuesta no responde a la pregunta original, pero complementa las respuestas útiles existentes al comparar el rendimiento .
Las soluciones se comparan solo en términos de velocidad de ejecución : los requisitos de memoria no se tienen en cuenta (varían de una solución a otra y pueden tener un gran número de repeticiones).
Resumen:
${var// /=}), ya que es prohibitivamente lento.Los siguientes son tiempos tomados en un iMac de finales de 2012 con una CPU Intel Core i5 de 3.2 GHz y una unidad Fusion, con OSX 10.10.4 y bash 3.2.57, y son el promedio de 1000 ejecuciones.
Las entradas son:
M... una solución potencialmente de múltiples caracteresS... una solución de un solo personajeP ... una solución compatible con 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
awky la utilidad múltiple perl.[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// /=}) es inexplicablemente lento con cadenas grandes, y ha sido eliminado de la ejecución (tomó alrededor de 50 minutos (!) En Bash 4.3.30, e incluso más en Bash 3.2.57 - Nunca esperé para terminar).(( i= 0; ... ))) son más lentos que los expandidos con llaves ( {1..n}), aunque los bucles aritméticos son más eficientes en cuanto a memoria.awkse refiere a BSD awk (como también se encuentra en OSX): es notablemente más lento que gawk(GNU Awk) y especialmentemawk .Aquí está el script Bash ( testrepeat) que produjo lo anterior. Se necesitan 2 argumentos:
En otras palabras: los tiempos anteriores se obtuvieron con testrepeat 100 1000ytestrepeat 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`👍
Hay más de una forma de hacerlo.
Usando un bucle:
La expansión de llaves se puede usar con literales enteros:
for i in {1..100}; do echo -n =; done Un bucle tipo C permite el uso de variables:
start=1
end=100
for ((i=$start; i<=$end; i++)); do echo -n =; doneUsando el printfincorporado:
printf '=%.0s' {1..100}
Especificar una precisión aquí trunca la cadena para que se ajuste al ancho especificado ( 0). Como printfreutiliza la cadena de formato para consumir todos los argumentos, esto simplemente imprime "="100 veces.
Usando head( printf, etc.) y tr:
head -c 100 < /dev/zero | tr '\0' '='
printf %100s | tr " " "="
head/ tr, que funciona bien incluso con recuentos altos de repetición (pequeña advertencia: head -cno es compatible con POSIX, pero BSD y GNU lo headimplementan); Si bien las otras dos soluciones serán lentas en ese caso, también tienen la ventaja de trabajar con cadenas de caracteres múltiples .
yesy head- útil si se desea un cierto número de saltos de línea: yes "" | head -n 100. trpuede hacer que imprima cualquier carácter:yes "" | head -n 100 | tr "\n" "="; echo
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/nulles significativamente más lento que la head -c100000000 < /dev/zero | tr '\0' '=' >/dev/nullversión. Por supuesto, debe usar un tamaño de bloque de 100M + para medir la diferencia de tiempo razonablemente. 100M bytes toman 1.7 sy 1 s con las dos versiones respectivas mostradas. Me quité el tr y lo descargué /dev/nully obtuve 0.287 s para la headversión y 0.675 s para la ddversión por mil millones 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;
Acabo de encontrar una manera realmente fácil de hacer esto usando seq:
ACTUALIZACIÓN: Esto funciona en el BSD seqque viene con OS X. YMMV con otras versiones
seq -f "#" -s '' 10
Imprimirá '#' 10 veces, así:
##########
-f "#"establece la cadena de formato para ignorar los números y solo imprimir #para cada uno.-s '' establece el separador en una cadena vacía para eliminar las nuevas líneas que se insertan entre cada número-fy -sparecen ser importantes.EDITAR: Aquí está en una función útil ...
repeat () {
seq -f $1 -s '' $2; echo
}
A lo que puedes llamar así ...
repeat "#" 10
NOTA: Si estás repitiendo #, ¡las citas son importantes!
seq: format ‘#’ has no % directive. seqes para números, no cadenas. Ver gnu.org/software/coreutils/manual/html_node/seq-invocation.html
seqse está reutilizando inteligentemente aquí para replicar cadenas : la cadena de formato que se pasa a -f, normalmente utilizada para formatear los números que se generan, contiene solo la cadena para replicar aquí, de modo que la salida contiene copias de esa cadena solamente. Desafortunadamente, GNU seqinsiste en la presencia de un formato de número en la cadena de formato, que es el error que está viendo.
"$1"(comillas dobles), para que también pueda pasar caracteres como '*'y cadenas con espacios en blanco incrustados. Finalmente, si desea poder usarlo %, debe duplicarlo (de lo contrario seq, pensará que es parte de una especificación de formato como %f); usando "${1//%/%%}"se encargaría de eso. Como (como mencionas) estás usando BSD seq , esto funcionará en sistemas operativos similares a BSD en general (por ejemplo, FreeBSD); por el contrario, no funcionará en Linux , donde se usa GNU seq .
Aquí hay dos formas interesantes:
ubuntu @ ubuntu: ~ $ yes = | cabeza -10 | pegar -s -d '' - ========== ubuntu @ ubuntu: ~ $ yes = | cabeza -10 | tr -d "\ n" ========== ubuntu @ ubuntu: ~ $
Tenga en cuenta que estos dos son sutilmente diferentes: el pastemétodo termina en una nueva línea. El trmétodo no lo hace.
paste requiere inexplicablemente -d '\0'para especificar un delimitador vacío, y falla con -d '': -d '\0'debería funcionar con todas las pasteimplementaciones compatibles con POSIX y, de hecho, también funciona con 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. Sin embargo, lo que es más importante: si está utilizando de printftodos modos, también puede printf '%.s=' $(seq 500)
No hay manera simple. Evite el uso de bucles printfy la sustitución.
str=$(printf "%40s")
echo ${str// /rep}
# echoes "rep" 40 times.
repl = 100, por ejemplo (no \nrepl() { local ts=$(printf "%${2}s"); printf %s "${ts// /$1}"; }
Si quieres POSIX-cumplimiento y la coherencia entre las diferentes implementaciones de echoy printf, y / o conchas que no sea sólo 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)
... producirá la misma salida que perl -E 'say "=" x 100'casi en todas partes.
seqno es una utilidad POSIX (aunque los sistemas BSD y Linux tienen implementaciones de la misma): en su lugar, puede hacer aritmética de shell POSIX con un whilebucle, como en la respuesta de @ Xennex81 (con printf "=", como sugiere correctamente, en lugar de echo -n).
cales POSIX seqno es. De todos modos, en lugar de reescribir la respuesta con un ciclo while (como dices, eso ya está en otras respuestas) agregaré una función RYO. Más educativo de esa manera ;-).
La pregunta era sobre cómo hacerlo con echo:
echo -e ''$_{1..100}'\b='
Esto hará exactamente lo mismo perl -E 'say "=" x 100'pero echosolo con .
Una manera pura de Bash sin eval , sin subcapas, sin herramientas externas, sin expansiones de llaves (es decir, puede tener el número para repetir en una variable):
Si le dan una variable nque se expande a un número (no negativo) y una variable pattern, por ejemplo,
$ n=5
$ pattern=hello
$ printf -v output '%*s' "$n"
$ output=${output// /$pattern}
$ echo "$output"
hellohellohellohellohello
Puedes hacer una función con esto:
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}"
}
Con este conjunto:
$ repeat 5 hello output
$ echo "$output"
hellohellohellohellohello
Para este pequeño truco estamos usando printfbastante con:
-v varname: en lugar de imprimir a la salida estándar, printfcolocará el contenido de la cadena formateada en variable varname.printfusará el argumento para imprimir el número correspondiente de espacios. Por ejemplo, printf '%*s' 42imprimirá 42 espacios.${var// /$pattern}se expandirá a la expansión de varcon todos los espacios reemplazados por la expansión de $pattern.También puede deshacerse de la tmpvariable en la repeatfunción utilizando la expansión indirecta:
repeat() {
# $1=number of patterns to repeat
# $2=pattern
# $3=output variable name
printf -v "$3" '%*s' "$1"
printf -v "$3" '%s' "${!3// /$2}"
}
bashlas operaciones de reemplazo de cadenas globales en el contexto de la expansión de parámetros ( ${var//old/new}) son particularmente lentas: terriblemente lento en bash 3.2.57y lento en bash 4.3.30, al menos en mi sistema OSX 10.10.3 en una máquina Intel Core i5 de 3.2 Ghz: con un recuento de 1,000, las cosas son lentas ( 3.2.57) / rápidas ( 4.3.30): 0.1 / 0.004 segundos. Aumentar la cuenta a 10,000 produce números sorprendentemente diferentes: repeat 10000 = vartoma alrededor de 80 segundos (!) En bash 3.2.57, y alrededor de 0.3 segundos en bash 4.3.30(mucho más rápido que encendido 3.2.57, pero aún lento).
#!/usr/bin/awk -f
BEGIN {
OFS = "="
NF = 100
print
}
O
#!/usr/bin/awk -f
BEGIN {
while (z++ < 100) printf "="
}
awk 'BEGIN { while (c++ < 100) printf "=" }'. Envuelta en una función de shell parametrizado (invoke como repeat 100 =, por ejemplo): repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { txt=substr(txt, 2); while (i++ < count) printf txt }'; }. (El .prefijo ficticio char y la substrllamada complementaria son necesarios para evitar un error en BSD awk, donde pasar un valor variable que comienza con =rompe el comando.)
NF = 100solución es muy inteligente (aunque para obtener 100 =, debe usar NF = 101). Las advertencias son que se estrella BSD awk(pero es muy rápido con gawky aún más rápido con mawk), y que se analizan en POSIX ni asignar a NF, ni el uso de los campos en BEGINlos bloques. Puede hacer que funcione también en BSD awkcon un ligero ajuste: awk 'BEGIN { OFS = "="; $101=""; print }'(pero curiosamente, en BSD awkeso no es más rápido que la solución de bucle). Como solución shell parametrizada: repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { OFS=substr(txt, 2); $(count+1)=""; print }'; }.
original-awkes el nombre bajo Linux del awk más antiguo similar al awk de BSD, que también se ha informado que se bloquea, si desea probar esto. Tenga en cuenta que el bloqueo suele ser el primer paso para encontrar un error explotable. Esta respuesta está promoviendo un código inseguro.
original-awkno es estándar y no se recomienda
awk NF=100 OFS='=' <<< ""(usando bashy gawk)
Supongo que el propósito original de la pregunta era hacer esto solo con los comandos integrados del shell. Así forbucles y printfs serían legítimos, mientras que rep, perly también jotmás adelante no lo haría. Aún así, el siguiente comando
jot -s "/" -b "\\" $((COLUMNS/2))
por ejemplo, imprime una línea de \/\/\/\/\/\/\/\/\/\/\/\/
jot -s '' -b '=' 100. La advertencia es que si bien las plataformas tipo BSD, incluido OSX, vienen con jot, las distribuciones de Linux no .
apt install athena-jotproporcionaría jot.
Como otros han dicho, en bash brace la expansión precede a la expansión de parámetros , por lo que los rangos solo pueden contener literales. y proporciona soluciones limpias, pero no son totalmente portátiles de un sistema a otro, incluso si está utilizando el mismo shell en cada uno. (Aunque está cada vez más disponible; por ejemplo, en FreeBSD 9.3 y superior ) y otras formas de indirección siempre funcionan, pero son algo poco elegantes.{m,n}seqjotseqeval
Afortunadamente, bash admite el estilo C para bucles (solo con expresiones aritméticas). Así que aquí hay una forma concisa de "puro golpe":
repecho() { for ((i=0; i<$1; ++i)); do echo -n "$2"; done; echo; }
Esto toma el número de repeticiones como el primer argumento y la cadena que se repetirá (que puede ser un solo carácter, como en la descripción del problema) como el segundo argumento. repecho 7 bsalidas bbbbbbb(terminadas por una nueva línea).
Dennis Williamson dio esencialmente esta solución hace cuatro años en su excelente respuesta a la creación de cadenas de caracteres repetidos en script de shell . El cuerpo de mi función difiere ligeramente del código allí:
Dado que el enfoque aquí está en repetir un solo carácter y el shell es bash, probablemente sea seguro usarlo en echolugar de hacerlo printf. Y leí la descripción del problema en esta pregunta como una preferencia por imprimir echo. La definición de función anterior funciona en bash y ksh93 . Aunque printfes más portátil (y generalmente debería usarse para este tipo de cosas), echola sintaxis de este es posiblemente más legible.
Las echofunciones integradas de algunos shells se interpretan -por sí mismas como una opción, aunque el significado habitual de -utilizar stdin para la entrada no tiene sentido echo. zsh hace esto. Y definitivamente existen correos electrónicos echoque no reconocen -n, ya que no es estándar . (Muchos proyectiles de estilo Bourne no aceptan el estilo C para los bucles, por lo tanto, echono es necesario considerar su comportamiento ...)
Aquí la tarea es imprimir la secuencia; allí , fue para asignarlo a una variable.
Si $nes el número deseado de repeticiones y no tiene que reutilizarlo, y desea algo aún más corto:
while ((n--)); do echo -n "$s"; done; echo
ndebe ser una variable; de esta manera no funciona con parámetros posicionales. $ses el texto a repetir.
printf "%100s" | tr ' ' '='Es óptimo.
zsh, por cierto El enfoque echo-in-a-loop funciona bien para recuentos de repetición más pequeños, pero para los más grandes existen alternativas compatibles con POSIX basadas en utilidades , como lo demuestra el comentario de @ Slomojo.
(while ((n--)); do echo -n "$s"; done; echo)
echointegrada que lo admite -n. El espíritu de lo que estás diciendo es absolutamente correcto. printfdebería preferirse casi siempre echo, al menos en uso no interactivo. Pero no creo que sea de ninguna manera inapropiado o engañoso dar una echorespuesta a una pregunta que hizo una y que proporcionó suficiente información para saber que funcionaría . Tenga en cuenta también que el soporte para ((n--))(sin a $) no está garantizado por POSIX.
Python es omnipresente y funciona igual en todas partes.
python -c "import sys; print('*' * int(sys.argv[1]))" "=" 100
El carácter y el recuento se pasan como parámetros separados.
python -c "import sys; print(sys.argv[1] * int(sys.argv[2]))" "=" 100
Otro medio para repetir una cadena arbitraria n veces:
Pros:
Contras:
yescomando de Gnu Core Utils .#!/usr/bin/sh
to_repeat='='
repeat_count=80
yes "$to_repeat" | tr -d '\n' | head -c "$repeat_count"
Con un terminal ANSI y caracteres US-ASCII para repetir. Puede usar una secuencia de escape ANSI CSI. Es la forma más rápida de repetir un personaje.
#!/usr/bin/env bash
char='='
repeat_count=80
printf '%c\e[%db' "$char" "$repeat_count"
O estáticamente:
Imprima una línea de 80 veces =:
printf '=\e[80b\n'
Limitaciones:
repeat_char secuencia ANSI CSI.repeat_charsecuencia ANSI CSI al carácter repetido.Esto es lo que uso para imprimir una línea de caracteres en la pantalla en Linux (según el ancho del terminal / pantalla)
printf '=%.0s' $(seq 1 $(tput cols))
Explicación:
Imprima un signo igual tantas veces como la secuencia dada:
printf '=%.0s' #sequence
Use la salida de un comando (esta es una característica bash llamada Sustitución de comandos):
$(example_command)
Da una secuencia, he usado del 1 al 20 como ejemplo. En el comando final se usa el comando tput en lugar de 20:
seq 1 20
Indique el número de columnas que se usan actualmente en la terminal:
tput cols
for i in {1..100}
do
echo -n '='
done
echo
Lo más simple es usar este one-liner en csh / tcsh:
printf "%50s\n" '' | tr '[:blank:]' '[=]'
Una alternativa más elegante a la solución Python propuesta podría ser:
python -c 'print "="*(1000)'
En caso de que desee repetir un carácter n veces siendo un número VARIABLE de veces dependiendo de, por ejemplo, la longitud de una cadena que puede hacer:
#!/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)
Muestra:
vari equals.............................: AB
Up to 10 positions I must fill with.....: 8 equal signs
AB========
lengthno funcionará expr, probablemente quisiste decir n=$(expr 10 - ${#vari}); Sin embargo, es más simple y más eficiente de utilizar expansión aritmética de Bash: n=$(( 10 - ${#vari} )). Además, en el centro de su respuesta está el enfoque de Perl en el que el OP está buscando una alternativa Bash .
Esta es la versión más larga de lo que Eliah Kagan estaba defendiendo:
while [ $(( i-- )) -gt 0 ]; do echo -n " "; done
Por supuesto, también puedes usar printf para eso, pero no es de mi agrado:
printf "%$(( i*2 ))s"
Esta versión es compatible con Dash:
until [ $(( i=i-1 )) -lt 0 ]; do echo -n " "; done
siendo yo el 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
}
Ejecuciones de muestra
$ repeatString 'a1' 10
a1a1a1a1a1a1a1a1a1a1
$ repeatString 'a1' 0
$ repeatString '' 10
Referencia lib en: https://github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash
Mi respuesta es un poco más complicada, y probablemente no sea perfecta, pero para aquellos que buscan generar grandes números, pude hacer alrededor de 10 millones en 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}
}
Lo más simple es usar este one-liner en bash:
seq 10 | xargs -n 1 | xargs -I {} echo -n ===\>;echo
La mayoría de las soluciones existentes en todo dependen de {1..10}apoyo sintaxis de la cáscara, que es bash- y zsh- específica, y no funciona en tcshOpenBSD de kshy la mayoría no fiestash .
Lo siguiente debería funcionar en OS X y todos los sistemas * BSD en cualquier shell; de hecho, puede usarse para generar una matriz completa de varios tipos de espacio decorativo:
$ printf '=%.0s' `jot 64` | fold -16
================
================
================
================$
Lamentablemente, no tenemos una nueva línea final; que se puede arreglar con un extra printf '\n'después del doblez:
$ printf "=%.0s" `jot 64` | fold -16 ; printf "\n"
================
================
================
================
$
Referencias
Mi propuesta (aceptando valores variables para n):
n=100
seq 1 $n | xargs -I {} printf =