¿Cómo podría hacer esto echo
?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'
opython -c 'print "=" * 100'
printf
con 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'
printf
con 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 =%.0s
que significa que siempre imprimirá uno =
sin importar el argumento que se le dé. Por lo tanto, imprime 100 =
s.
repl = 100
, por ejemplo ( eval
se requiere truco, desafortunadamente, para basar la expansión de repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
seq
lugar, por ejemplo $(seq 1 $limit)
.
$s%.0s
para %.0s$s
que los guiones causen un printf
error.
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
tr
es la única solución POSIX porque seq
, yes
y {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 " seq
no 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
awk
y 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.awk
se 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 1000
ytestrepeat 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 =; done
Usando el printf
incorporado:
printf '=%.0s' {1..100}
Especificar una precisión aquí trunca la cadena para que se ajuste al ancho especificado ( 0
). Como printf
reutiliza 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 -c
no es compatible con POSIX, pero BSD y GNU lo head
implementan); 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 .
yes
y head
- útil si se desea un cierto número de saltos de línea: yes "" | head -n 100
. tr
puede hacer que imprima cualquier carácter:yes "" | head -n 100 | tr "\n" "="; echo
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
es significativamente más lento que la head -c100000000 < /dev/zero | tr '\0' '=' >/dev/null
versió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/null
y obtuve 0.287 s para la head
versión y 0.675 s para la dd
versió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 seq
que 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-f
y -s
parecen 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
. seq
es para números, no cadenas. Ver gnu.org/software/coreutils/manual/html_node/seq-invocation.html
seq
se 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 seq
insiste 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 paste
método termina en una nueva línea. El tr
mé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 paste
implementaciones 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 printf
todos modos, también puede printf '%.s=' $(seq 500)
No hay manera simple. Evite el uso de bucles printf
y la sustitución.
str=$(printf "%40s")
echo ${str// /rep}
# echoes "rep" 40 times.
repl = 100
, por ejemplo (no \n
repl() { local ts=$(printf "%${2}s"); printf %s "${ts// /$1}"; }
Si quieres POSIX-cumplimiento y la coherencia entre las diferentes implementaciones de echo
y 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.
seq
no 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 while
bucle, como en la respuesta de @ Xennex81 (con printf "="
, como sugiere correctamente, en lugar de echo -n
).
cal
es POSIX seq
no 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 echo
solo 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 n
que 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 printf
bastante con:
-v varname
: en lugar de imprimir a la salida estándar, printf
colocará el contenido de la cadena formateada en variable varname
.printf
usará el argumento para imprimir el número correspondiente de espacios. Por ejemplo, printf '%*s' 42
imprimirá 42 espacios.${var// /$pattern}
se expandirá a la expansión de var
con todos los espacios reemplazados por la expansión de $pattern
.También puede deshacerse de la tmp
variable en la repeat
funció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}"
}
bash
las 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.57
y 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 = var
toma 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 substr
llamada complementaria son necesarios para evitar un error en BSD awk
, donde pasar un valor variable que comienza con =
rompe el comando.)
NF = 100
solució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 gawk
y 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 BEGIN
los bloques. Puede hacer que funcione también en BSD awk
con un ligero ajuste: awk 'BEGIN { OFS = "="; $101=""; print }'
(pero curiosamente, en BSD awk
eso 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-awk
es 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-awk
no es estándar y no se recomienda
awk NF=100 OFS='=' <<< ""
(usando bash
y gawk
)
Supongo que el propósito original de la pregunta era hacer esto solo con los comandos integrados del shell. Así for
bucles y printf
s serían legítimos, mientras que rep
, perl
y también jot
má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-jot
proporcionarí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}
seq
jot
seq
eval
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 b
salidas 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 echo
lugar 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 printf
es más portátil (y generalmente debería usarse para este tipo de cosas), echo
la sintaxis de este es posiblemente más legible.
Las echo
funciones 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 echo
que 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, echo
no es necesario considerar su comportamiento ...)
Aquí la tarea es imprimir la secuencia; allí , fue para asignarlo a una variable.
Si $n
es 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
n
debe ser una variable; de esta manera no funciona con parámetros posicionales. $s
es 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)
echo
integrada que lo admite -n
. El espíritu de lo que estás diciendo es absolutamente correcto. printf
deberí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 echo
respuesta 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:
yes
comando 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_char
secuencia 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========
length
no 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 tcsh
OpenBSD de ksh
y 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 =