Come potrei farlo con echo
?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'
opython -c 'print "=" * 100'
printf
con seq
)svrb=`printf '%.sv' $(seq $vrb)`
Come potrei farlo con echo
?
perl -E 'say "=" x 100'
ruby -e 'puts "=" * 100'
opython -c 'print "=" * 100'
printf
con seq
)svrb=`printf '%.sv' $(seq $vrb)`
Risposte:
Puoi usare:
printf '=%.0s' {1..100}
Come funziona:
Bash espande {1..100} in modo che il comando diventi:
printf '=%.0s' 1 2 3 4 ... 100
Ho impostato il formato di printf sul =%.0s
quale significa che verrà sempre stampato un singolo, =
indipendentemente dall'argomento che viene fornito. Pertanto stampa 100 =
s.
repl = 100
, ad esempio ( eval
è necessario un trucco, purtroppo, per basare l'espansione del controvento su una variabile):repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
seq
invece ad es $(seq 1 $limit)
.
$s%.0s
al %.0s$s
contrario trattini causare un printf
errore.
printf
: continua ad applicare la stringa di formato fino a quando non rimangono più argomenti. Avevo assunto che elaborasse la stringa di formato solo una volta!
Nessun modo semplice. Ma per esempio:
seq -s= 100|tr -d '[:digit:]'
O forse un modo conforme agli standard:
printf %100s |tr " " "="
C'è anche un tput rep
, ma per quanto riguarda i miei terminali a portata di mano (xterm e linux) non sembrano supportarlo :)
=
caratteri.
printf
tr
è l'unica soluzione POSIX, perché seq
, yes
e {1..3}
non sono POSIX.
printf %100s | sed 's/ /abc/g'
- genera "abcabcabc ..."
tr
). Potresti anche estenderlo a qualcosa del genere printf "%${COLUMNS}s\n" | tr " " "="
.
wc
. L'unica conclusione che posso trarre da questo è " seq
non dovrebbe essere usato".
Punta del cappello a @ gniourf_gniourf per il suo contributo.
Nota: questa risposta non risponde alla domanda originale, ma integra le risposte esistenti e utili confrontando le prestazioni .
Le soluzioni vengono confrontate solo in termini di velocità di esecuzione - i requisiti di memoria non vengono presi in considerazione (variano in base alle soluzioni e possono avere un numero elevato di ripetizioni).
Sommario:
${var// /=}
), Poiché è proibitivamente lento.Di seguito sono riportati i tempi presi su un iMac di fine 2012 con una CPU Intel Core i5 da 3,2 GHz e un Fusion Drive, con OSX 10.10.4 e bash 3.2.57, e sono la media di 1000 corse.
Le voci sono:
M
... una soluzione potenzialmente multi- carattereS
... una soluzione a singolo carattereP
... una soluzione conforme a 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 le perl
soluzioni.[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// /=}
) di Bash è inspiegabilmente lenta con stringhe di grandi dimensioni, ed è stata rimossa dalla corsa (impiegata circa 50 minuti (!) In Bash 4.3.30 e ancora più lunga in Bash 3.2.57 - Non ho mai aspettato per finire).(( i= 0; ... ))
) sono più lenti di quelli espansi con parentesi graffe ( {1..n}
) - sebbene i loop aritmetici siano più efficienti in termini di memoria.awk
si riferisce a BSD awk
(come si trova anche su OSX) - è notevolmente più lento di gawk
(GNU Awk) e soprattutto mawk
.Ecco lo script Bash ( testrepeat
) che ha prodotto quanto sopra. Sono necessari 2 argomenti:
In altre parole: i tempi sopra sono stati ottenuti con 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`
👍
C'è più di un modo per farlo.
Utilizzando un loop:
L'espansione del controvento può essere utilizzata con valori letterali interi:
for i in {1..100}; do echo -n =; done
Un ciclo di tipo C consente l'uso di variabili:
start=1
end=100
for ((i=$start; i<=$end; i++)); do echo -n =; done
Utilizzando il printf
built-in:
printf '=%.0s' {1..100}
Specificando una precisione qui viene troncata la stringa per adattarla alla larghezza specificata ( 0
). Poiché printf
riutilizza la stringa di formato per consumare tutti gli argomenti, questa viene semplicemente stampata "="
100 volte.
Utilizzando head
( printf
, ecc.) E tr
:
head -c 100 < /dev/zero | tr '\0' '='
printf %100s | tr " " "="
head
/ tr
, che funziona bene anche con conteggi ripetuti elevati (piccolo avvertimento: head -c
non è conforme a POSIX, ma sia BSD che GNU la head
implementano); mentre le altre due soluzioni saranno lente in quel caso, hanno anche il vantaggio di lavorare con stringhe multi- carattere.
yes
e head
- utile se si desidera un certo numero di nuove righe: yes "" | head -n 100
. tr
può farlo stampare qualsiasi personaggio:yes "" | head -n 100 | tr "\n" "="; echo
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
è significativamente più lento della head -c100000000 < /dev/zero | tr '\0' '=' >/dev/null
versione. Ovviamente devi usare una dimensione del blocco di 100 M + per misurare ragionevolmente la differenza di tempo. 100 M byte richiedono 1,7 se 1 s con le due rispettive versioni mostrate. Ho tolto il tr e l'ho appena scaricato /dev/null
e ho ottenuto 0,287 s per la head
versione e 0,675 s per la dd
versione per un miliardo di byte.
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
=> 0,21332 s, 469 MB/s
; Per: dd if=/dev/zero count=100 bs=1000000| tr '\0' '=' >/dev/null
=> 0,161579 s, 619 MB/s
;
Ho appena trovato un modo davvero semplice per farlo usando seq:
AGGIORNAMENTO: funziona con BSD seq
fornito con OS X. YMMV con altre versioni
seq -f "#" -s '' 10
Stampa '#' 10 volte, in questo modo:
##########
-f "#"
imposta la stringa di formato per ignorare i numeri e stampare solo #
per ognuno.-s ''
imposta il separatore su una stringa vuota per rimuovere le nuove righe che seq inserisce tra ciascun numero-f
e -s
sembrano essere importanti.EDIT: qui è in una comoda funzione ...
repeat () {
seq -f $1 -s '' $2; echo
}
Che puoi chiamare così ...
repeat "#" 10
NOTA: se stai ripetendo #
le virgolette sono importanti!
seq: format ‘#’ has no % directive
. seq
è per i numeri, non per le stringhe. Vedi gnu.org/software/coreutils/manual/html_node/seq-invocation.html
seq
viene abilmente riproposto qui per replicare le stringhe : la stringa di formato passata a -f
- normalmente usata per formattare i numeri generati - contiene solo la stringa da replicare qui in modo che l'output contenga solo copie di quella stringa. Sfortunatamente, GNU seq
insiste sulla presenza di un formato numerico nella stringa di formato, che è l'errore che stai vedendo.
"$1"
(virgolette doppie), in modo da poter passare anche caratteri come '*'
e stringhe con spazi bianchi incorporati. Infine, se vuoi essere in grado di usarlo %
, devi raddoppiarlo (altrimenti seq
penserai che sia parte di una specifica di formato come %f
); l'uso se "${1//%/%%}"
ne occuperebbe. Dal momento che (come dici tu) stai usando BSD seq
, questo funzionerà su sistemi operativi simili a BSD in generale (ad esempio, FreeBSD) - al contrario, non funzionerà su Linux , dove GNU seq
è usato.
Ecco due modi interessanti:
ubuntu @ ubuntu: ~ $ yes = | testa -10 | incolla -s -d '' - ========== ubuntu @ ubuntu: ~ $ yes = | testa -10 | tr -d "\ n" ========== ubuntu @ ubuntu: ~ $
Nota che questi due sono leggermente diversi: il paste
metodo termina in una nuova riga. Il tr
metodo no.
paste
richiede inspiegabilmente -d '\0'
per specificare un delimitatore vuoto e non riesce con -d ''
- -d '\0'
dovrebbe funzionare con tutte le paste
implementazioni compatibili con POSIX e in effetti funziona anche 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
. Ancora più importante, tuttavia: se si utilizza printf
comunque, è possibile anche seguire l'approccio più semplice ed efficiente dalla risposta accettata:printf '%.s=' $(seq 500)
Non esiste un modo semplice. Evitare l'uso printf
e la sostituzione di loop .
str=$(printf "%40s")
echo ${str// /rep}
# echoes "rep" 40 times.
repl = 100
, ad esempio (non \n
repl() { local ts=$(printf "%${2}s"); printf %s "${ts// /$1}"; }
Se si desidera la conformità POSIX e la coerenza tra diverse implementazioni di echo
e printf
, e / o shell diverse dal solo 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)
... produrrà lo stesso output di perl -E 'say "=" x 100'
quasi ovunque.
seq
non si tratta di un'utilità POSIX (sebbene i sistemi BSD e Linux ne abbiano implementazioni) - puoi invece eseguire l'aritmetica della shell POSIX con un while
ciclo, come nella risposta di @ Xennex81 (con printf "="
, come giustamente suggerito, piuttosto che echo -n
).
cal
è POSIX. seq
non è. Comunque, piuttosto che riscrivere la risposta con un ciclo while (come dici tu, che è già in altre risposte) aggiungerò una funzione RYO. Più educativo in quel modo ;-).
La domanda era su come farlo con echo
:
echo -e ''$_{1..100}'\b='
Questo farà esattamente lo stesso perl -E 'say "=" x 100'
ma echo
solo con .
Un modo puro di Bash senza no eval
, subshells, senza strumenti esterni, senza espansioni di parentesi graffe (cioè, puoi avere il numero da ripetere in una variabile):
Se ti viene data una variabile n
che si espande in un numero (non negativo) e una variabile pattern
, ad es.
$ n=5
$ pattern=hello
$ printf -v output '%*s' "$n"
$ output=${output// /$pattern}
$ echo "$output"
hellohellohellohellohello
Puoi fare una funzione con questo:
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 questo set:
$ repeat 5 hello output
$ echo "$output"
hellohellohellohellohello
Per questo piccolo trucco stiamo usando printf
parecchio con:
-v varname
: anziché stampare sull'output standard, printf
il contenuto della stringa formattata verrà modificato in variabile varname
.printf
utilizzerà l'argomento per stampare il numero corrispondente di spazi. Ad esempio, printf '%*s' 42
stamperà 42 spazi.${var// /$pattern}
si espanderà all'espansione di var
con tutti gli spazi sostituiti dall'espansione di $pattern
.Puoi anche eliminare la tmp
variabile nella repeat
funzione usando l'espansione indiretta:
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
le operazioni di sostituzione globale delle stringhe nel contesto dell'espansione dei parametri ( ${var//old/new}
) siano particolarmente lente: estremamente lento in bash 3.2.57
e lento in bash 4.3.30
, almeno sul mio sistema OSX 10.10.3 su una macchina Intel Core i5 da 3,2 Ghz: Con un conteggio di 1.000, le cose sono lente ( 3.2.57
) / veloci ( 4.3.30
): 0,1 / 0,004 secondi. Aumentare il conteggio a 10.000 produce numeri sorprendentemente diversi: repeat 10000 = var
impiega circa 80 secondi (!) In bash 3.2.57
e circa 0,3 secondi in bash 4.3.30
(molto più veloce che in attivo 3.2.57
, ma comunque 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 "=" }'
. Avvolto in una funzione shell parametrizzata (invoke come repeat 100 =
, per esempio): repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { txt=substr(txt, 2); while (i++ < count) printf txt }'; }
. (Il .
prefisso fittizio char e la substr
chiamata complementare sono necessari per aggirare un bug in BSD awk
, dove passare un valore variabile che inizia con =
interrompe il comando.)
NF = 100
soluzione è molto intelligente (anche se per ottenere 100 =
, è necessario utilizzare NF = 101
). Gli avvertimenti sono che si blocca BSD awk
(ma è molto veloce con gawk
e ancora più veloce con mawk
), e che discute POSIX né assegnazione di NF
, né l'uso di campi in BEGIN
blocchi. Puoi farlo funzionare anche in BSD awk
con una leggera modifica: awk 'BEGIN { OFS = "="; $101=""; print }'
(ma curiosamente, in BSD awk
che non è più veloce della soluzione loop). Come soluzione shell parametri: repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { OFS=substr(txt, 2); $(count+1)=""; print }'; }
.
original-awk
è il nome sotto Linux del awk anziani simile a awk di BSD, che è stata riportata anche in crash, se si vuole provare questo. Si noti che l'arresto anomalo di solito è il primo passo verso la ricerca di un bug sfruttabile. Questa risposta sta promuovendo così un codice insicuro.
original-awk
non è standard e non è raccomandato
awk NF=100 OFS='=' <<< ""
(usando bash
e gawk
)
Immagino che lo scopo originale della domanda fosse quello di farlo solo con i comandi integrati della shell. Così for
loop e printf
s sarebbe legittimo, mentre rep
, perl
e anche jot
al di sotto no. Tuttavia, il seguente comando
jot -s "/" -b "\\" $((COLUMNS/2))
ad esempio, stampa una riga di \/\/\/\/\/\/\/\/\/\/\/\/
jot -s '' -b '=' 100
. L'avvertenza è che mentre le piattaforme simili a BSD, incluso OSX, arrivano jot
, le distribuzioni Linux no .
apt install athena-jot
fornirebbe jot
.
Come altri hanno già detto, in bash l' espansione del parentesi precede l' espansione dei parametri , quindi gli intervalli possono contenere solo valori letterali. e fornire soluzioni pulite ma non sono completamente portatili da un sistema all'altro, anche se si utilizza la stessa shell su ciascuno. (Anche se è sempre più disponibile; ad esempio, in FreeBSD 9.3 e versioni successive .) E altre forme di indiretta funzionano sempre ma sono in qualche modo ineleganti.{m,n}
seq
jot
seq
eval
Fortunatamente, bash supporta lo stile C per i loop (solo con espressioni aritmetiche). Quindi ecco un modo conciso di "puro bash":
repecho() { for ((i=0; i<$1; ++i)); do echo -n "$2"; done; echo; }
Questo prende il numero di ripetizioni come primo argomento e la stringa da ripetere (che può essere un singolo carattere, come nella descrizione del problema) come secondo argomento. repecho 7 b
uscite bbbbbbb
(terminate da una nuova riga).
Dennis Williamson ha dato essenzialmente questa soluzione quattro anni fa nella sua eccellente risposta alla creazione di una serie di personaggi ripetuti nello script di shell . Il mio corpo della funzione differisce leggermente dal codice lì:
Dato che il focus qui è sulla ripetizione di un singolo personaggio e la shell è bash, è probabilmente sicuro da usare echo
invece di printf
. E ho letto la descrizione del problema in questa domanda come espressione di una preferenza con cui stampare echo
. La definizione della funzione sopra funziona in bash e ksh93 . Sebbene printf
sia più portatile (e di solito dovrebbe essere usato per questo genere di cose), echo
la sintassi è probabilmente più leggibile.
I echo
builtin di alcune shell interpretano -
da soli come un'opzione - anche se il solito significato di -
, usare stdin per l'input, non ha senso echo
. zsh fa questo. E sicuramente esistono echo
s che non riconoscono -n
, in quanto non è standard . (Molte shell in stile Bourne non accettano affatto lo stile C per i loop, quindi il loro echo
comportamento non deve essere considerato.)
Qui il compito è stampare la sequenza; lì , era per assegnarlo a una variabile.
Se $n
è il numero desiderato di ripetizioni e non è necessario riutilizzarlo e si desidera qualcosa di ancora più breve:
while ((n--)); do echo -n "$s"; done; echo
n
deve essere una variabile - in questo modo non funziona con i parametri posizionali. $s
è il testo da ripetere.
printf "%100s" | tr ' ' '='
è ottimale.
zsh
anche, per inciso. L'approccio echo-in-a-loop funziona bene per conteggi ripetuti più piccoli, ma per quelli più grandi ci sono alternative conformi a POSIX basate sulle utility , come evidenziato dal commento di @ Slomojo.
(while ((n--)); do echo -n "$s"; done; echo)
echo
builtin che supporta -n
. Lo spirito di ciò che stai dicendo è assolutamente corretto. printf
dovrebbe quasi sempre essere preferito echo
, almeno nell'uso non interattivo. Ma non penso che sia stato in alcun modo inappropriato o fuorviante dare una echo
risposta a una domanda che lo ha posto e che ha fornito informazioni sufficienti per sapere che avrebbe funzionato . Si noti inoltre che il supporto per ((n--))
(senza a $
) non è garantito da POSIX.
Python è onnipresente e funziona allo stesso modo ovunque.
python -c "import sys; print('*' * int(sys.argv[1]))" "=" 100
Carattere e conteggio vengono passati come parametri separati.
python -c "import sys; print(sys.argv[1] * int(sys.argv[2]))" "=" 100
Un altro mezzo per ripetere una stringa arbitraria n volte:
Professionisti:
Contro:
yes
comando di Gnu Core Utils .#!/usr/bin/sh
to_repeat='='
repeat_count=80
yes "$to_repeat" | tr -d '\n' | head -c "$repeat_count"
Con un terminale ANSI e caratteri US-ASCII da ripetere. È possibile utilizzare una sequenza di escape CSI ANSI. È il modo più veloce per ripetere un personaggio.
#!/usr/bin/env bash
char='='
repeat_count=80
printf '%c\e[%db' "$char" "$repeat_count"
O staticamente:
Stampa una riga di 80 volte =
:
printf '=\e[80b\n'
limitazioni:
repeat_char
sequenza ANSI CSI.repeat_char
sequenza ANSI CSI nel carattere ripetuto.Ecco cosa uso per stampare una riga di caratteri sullo schermo in Linux (in base alla larghezza del terminale / schermo)
printf '=%.0s' $(seq 1 $(tput cols))
Spiegazione:
Stampa un segno di uguale quante volte la sequenza indicata:
printf '=%.0s' #sequence
Usa l'output di un comando (questa è una funzione bash chiamata Sostituzione comandi):
$(example_command)
Dai una sequenza, ho usato da 1 a 20 come esempio. Nel comando finale viene utilizzato il comando tput invece di 20:
seq 1 20
Indica il numero di colonne attualmente utilizzate nel terminale:
tput cols
for i in {1..100}
do
echo -n '='
done
echo
Il più semplice è usare questo one-liner in csh / tcsh:
printf "%50s\n" '' | tr '[:blank:]' '[=]'
Un'alternativa più elegante alla soluzione Python proposta potrebbe essere:
python -c 'print "="*(1000)'
Nel caso in cui desideri ripetere un carattere n volte essendo na VARIABILE numero di volte a seconda, diciamo, della lunghezza di una stringa che puoi fare:
#!/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)
Visualizza:
vari equals.............................: AB
Up to 10 positions I must fill with.....: 8 equal signs
AB========
length
non funzionerà expr
, probabilmente intendevi n=$(expr 10 - ${#vari})
; tuttavia, è più semplice e più efficiente di utilizzare l'espansione aritmetica di Bash: n=$(( 10 - ${#vari} ))
. Inoltre, al centro della tua risposta c'è l'approccio molto Perl a cui l'OP sta cercando un'alternativa Bash .
Questa è la versione più lunga di ciò che Eliah Kagan stava sposando:
while [ $(( i-- )) -gt 0 ]; do echo -n " "; done
Ovviamente puoi usare printf anche per quello, ma non per i miei gusti:
printf "%$(( i*2 ))s"
Questa versione è compatibile Dash:
until [ $(( i=i-1 )) -lt 0 ]; do echo -n " "; done
con il numero iniziale.
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
}
Esecuzioni campione
$ repeatString 'a1' 10
a1a1a1a1a1a1a1a1a1a1
$ repeatString 'a1' 0
$ repeatString '' 10
Lib di riferimento su: https://github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash
La mia risposta è un po 'più complicata, e probabilmente non perfetta, ma per coloro che cercano di produrre grandi numeri, sono stato in grado di fare circa 10 milioni in 3 secondi.
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}
}
Il più semplice è usare questo one-liner in bash:
seq 10 | xargs -n 1 | xargs -I {} echo -n ===\>;echo
La maggior parte delle soluzioni esistenti dipendono tutte dal {1..10}
supporto della sintassi della shell, che è bash
- e zsh
- specifica, e non funziona in tcsh
OpenBSD ksh
e la maggior parte non-bash sh
.
Quanto segue dovrebbe funzionare su OS X e su tutti i sistemi * BSD in qualsiasi shell; infatti, può essere utilizzato per generare un'intera matrice di vari tipi di spazio decorativo:
$ printf '=%.0s' `jot 64` | fold -16
================
================
================
================$
Purtroppo, non abbiamo una nuova riga finale; che può essere risolto con un extra printf '\n'
dopo il fold:
$ printf "=%.0s" `jot 64` | fold -16 ; printf "\n"
================
================
================
================
$
Riferimenti:
La mia proposta (accettando valori variabili per n):
n=100
seq 1 $n | xargs -I {} printf =