pas avec écho, mais sur le même sujet ruby -e 'puts "=" * 100'oupython -c 'print "=" * 100'
Evgeny
1
Grande question. Très bonnes réponses. J'ai utilisé une des réponses dans un vrai travail ici, que je posterai comme exemple: github.com/drbeco/oldfiles/blob/master/oldfiles (utilisé printfavec seq)svrb=`printf '%.sv' $(seq $vrb)`
Dr Beco
Une solution générique pour imprimer quoi que ce soit (1 ou plusieurs caractères, même les sauts de ligne): Repeat_this () {i = 1; while ["$ i" -le "$ 2"]; faire printf "% s" "$ 1"; i = $ (($ i + 1)); terminé ; printf '\ n';}. Utilisez comme ceci: Repeat_this "something" Number_of_repetitions. Par exemple, pour présenter la répétition de 5 fois quelque chose, y compris 3 sauts de ligne: Repeat_this "$ (printf '\ n \ n \ nthis')" 5. Le dernier printf '\ n' peut être retiré (mais je l'ai mis pour créer des fichiers texte, et ceux-ci ont besoin d'une nouvelle ligne comme dernier caractère!)
Olivier Dulac
Réponses:
396
Vous pouvez utiliser:
printf '=%.0s'{1..100}
Comment cela fonctionne:
Bash développe {1..100} de sorte que la commande devient:
printf '=%.0s'1234...100
J'ai défini le format de printf, =%.0sce qui signifie qu'il imprimera toujours un seul, =quel que soit l'argument qui lui est donné. Il imprime donc 100 =s.
Excellente solution qui fonctionne raisonnablement bien même avec de grands nombres de répétitions. Voici un wrapper de fonction avec lequel vous pouvez invoquer repl = 100, par exemple (une evalastuce est malheureusement nécessaire pour baser l'expansion d'accolade sur une variable):repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
mklement0
7
Est-il possible de fixer la limite supérieure à l'aide d'un var? J'ai essayé et je n'arrive pas à le faire fonctionner.
Mike Purcell
70
Vous ne pouvez pas utiliser de variables dans l'extension d'accolade. Utilisez seqplutôt par exemple $(seq 1 $limit).
dogbane
11
Si vous le fonctionnalisez, il est préférable de le réorganiser de $s%.0sà %.0s$ssinon les tirets provoquent une printferreur.
KomodoDave
5
Cela m'a fait remarquer un comportement de Bash printf: il continue d'appliquer la chaîne de format jusqu'à ce qu'il n'y ait plus d'arguments. J'avais supposé qu'il n'avait traité la chaîne de format qu'une seule fois!
Jeenu
89
Pas facile. Mais par exemple:
seq -s=100|tr -d '[:digit:]'
Ou peut-être d'une manière conforme aux normes:
printf %100s|tr " ""="
Il y en a aussi un tput rep, mais quant à mes terminaux à portée de main (xterm et linux) ils ne semblent pas le supporter :)
Notez que la première option avec seq imprime une de moins que le nombre donné, de sorte que l'exemple imprime 99 =caractères.
Camilo Martin
13
printftrest la seule solution POSIX car seq, yeset {1..3}ne sont pas POSIX.
Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
2
Pour répéter une chaîne plutôt qu'un simple caractère: printf %100s | sed 's/ /abc/g'- affiche 'abcabcabc ...'
John Rix
3
+1 pour n'utiliser aucune boucle et une seule commande externe ( tr). Vous pouvez également l'étendre à quelque chose comme printf "%${COLUMNS}s\n" | tr " " "=".
musiphil
2
@ mklement0 Eh bien, j'espérais que vous comptiez la dernière nouvelle ligne par erreur avec wc. La seule conclusion que je peux en tirer est " seqne devrait pas être utilisée".
Remarque: Cette réponse ne répond pas à la question d'origine, mais complète les réponses utiles existantes en comparant les performances .
Les solutions sont comparées uniquement en termes de vitesse d'exécution - les besoins en mémoire ne sont pas pris en compte (ils varient selon les solutions et peuvent être importants avec de grands nombres de répétitions).
Résumé:
Si votre nombre de répétitions est faible , disons jusqu'à environ 100, cela vaut la peine d'aller avec les solutions Bash uniquement , car le coût de démarrage des utilitaires externes est important, en particulier celui de Perl.
Cependant, si vous n'avez besoin que d' une seule instance de répétition de caractères, toutes les solutions existantes peuvent convenir.
Avec de grands nombres de répétitions , utilisez des utilitaires externes , car ils seront beaucoup plus rapides.
En particulier, évitez le remplacement global de la sous-chaîne de Bash par de grandes chaînes
(par exemple, ${var// /=}), car il est extrêmement lent.
Les temporisations suivantes sont prises sur un iMac fin 2012 avec un processeur Intel Core i5 à 3,2 GHz et un Fusion Drive, exécutant OSX 10.10.4 et bash 3.2.57, et représentent la moyenne de 1000 exécutions.
Les entrées sont:
répertorié par ordre croissant de durée d'exécution (le plus rapide en premier)
préfixé par:
M... une solution potentiellement multi- caractères
S... une seule solution -character seule
P ... une solution compatible POSIX
suivi d'une brève description de la solution
suffixé du nom de l'auteur de la réponse d'origine
Les solutions Bash uniquement mènent le peloton - mais seulement avec un nombre de répétitions aussi petit! (voir ci-dessous).
Le coût de démarrage des utilitaires externes importe ici, en particulier celui de Perl. Si vous devez appeler cela en boucle - avec de petits nombres de répétitions à chaque itération - évitez le multi-utilitaire awket les perlsolutions.
La solution Perl de la question est de loin la plus rapide.
Le remplacement global des chaînes de Bash ( ${foo// /=}) est inexplicablement lent avec des chaînes de grande taille, et a été retiré du jeu (a pris environ 50 minutes (!) Dans Bash 4.3.30, et encore plus longtemps dans Bash 3.2.57 - je n'ai jamais attendu pour finir).
Les boucles de bash sont lentes et les boucles arithmétiques ( (( i= 0; ... ))) sont plus lentes que celles à croisillons ( {1..n}) - bien que les boucles arithmétiques soient plus efficaces en mémoire.
awkfait référence à BSDawk (comme on le trouve également sur OSX) - il est sensiblement plus lent que gawk(GNU Awk) et surtout mawk.
Notez qu'avec de grands nombres et plusieurs caractères. cordes, la consommation de mémoire peut devenir une considération - les approches diffèrent à cet égard.
Voici le script Bash ( testrepeat) qui a produit ce qui précède. Il faut 2 arguments:
le nombre de répétitions de caractères
facultativement, le nombre de tests à effectuer et de calculer le temps moyen à partir de
En d'autres termes: les timings ci-dessus ont été obtenus avec testrepeat 100 1000ettestrepeat 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++));dofor((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=12>/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;doif[[-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"donefidone
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=1if(( skip ));then
echo 'n/a'>&2else
time for(( n =0; n < COUNT_RUNS; n++));do{ printf -v t "%${COUNT_REPETITIONS}s"'='; printf %s "${t// /=}";}>"$outFile"donefi}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
Il est intéressant de voir la comparaison de synchronisation, mais je pense que dans de nombreux programmes, la sortie est tamponnée, de sorte que leur synchronisation peut être modifiée si la mise en mémoire tampon a été désactivée.
Sergiy Kolodyazhnyy
In order to use brace expansion with a variable, we must use `eval`👍
pyb
2
Ainsi, la solution perl (sid_com) est fondamentalement la plus rapide ... une fois que la surcharge initiale de lancement de perl est atteinte. (il passe de 59 ms pour une petite répétition à 67 ms pour un million de répétitions ... donc le perl forking a pris environ 59 ms sur votre système)
Olivier Dulac
46
Il y a plus d'une façon de le faire.
Utiliser une boucle:
L'expansion d'accolade peut être utilisée avec des littéraux entiers:
for i in{1..100};do echo -n =;done
Une boucle de type C permet l'utilisation de variables:
La spécification d'une précision ici tronque la chaîne pour l'adapter à la largeur spécifiée ( 0). Comme printfréutilise la chaîne de format pour consommer tous les arguments, cela imprime simplement "="100 fois.
++ pour la solution head/ tr, qui fonctionne bien même avec un nombre de répétitions élevé (petite mise en garde: head -cn'est pas compatible POSIX, mais BSD et GNU l' headimplémentent); alors que les deux autres solutions seront lentes dans ce cas, elles ont également l'avantage de fonctionner avec des chaînes multi- caractères.
mklement0
1
L' utilisation yeset head- utile si vous voulez un certain nombre de nouvelles lignes: yes "" | head -n 100. trpeut faire imprimer n'importe quel caractère:yes "" | head -n 100 | tr "\n" "="; echo
loxaxs
Un peu surprenant: dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/nullest beaucoup plus lent que la head -c100000000 < /dev/zero | tr '\0' '=' >/dev/nullversion. Bien sûr, vous devez utiliser une taille de bloc de 100M + pour mesurer la différence de temps de manière raisonnable. 100M octets prend 1,7 s et 1 s avec les deux versions respectives illustrées. J'ai enlevé le tr et je l'ai simplement vidé /dev/nullet j'ai obtenu 0,287 s pour la headversion et 0,675 s pour la ddversion pour un milliard d'octets.
Ah, donc j'utilisais la version BSD de seq trouvée sur OS X. Je mettrai à jour la réponse. Quelle version utilisez-vous?
Sam Salisbury
J'utilise seq de GNU coreutils.
John B
1
@JohnB: BSD seqest intelligemment réutilisé ici pour répliquer les chaînes : la chaîne de format transmise à -f- normalement utilisée pour formater les nombres générés - contient uniquement la chaîne à répliquer ici afin que la sortie contienne uniquement des copies de cette chaîne. Malheureusement, GNU seqinsiste sur la présence d'un format numérique dans la chaîne de format, ce qui est l'erreur que vous voyez.
mklement0
1
Bien fait; fonctionne également avec des chaînes multi- caractères. Veuillez utiliser "$1"(guillemets doubles), afin que vous puissiez également passer des caractères tels que '*'et des chaînes avec des espaces blancs intégrés. Enfin, si vous voulez pouvoir l'utiliser %, vous devez le doubler (sinon vous seqpenserez que cela fait partie d'une spécification de format telle que %f); utiliser s'en "${1//%/%%}"occuperait. Puisque (comme vous le mentionnez) vous utilisez BSDseq , cela fonctionnera sur les systèmes d'exploitation de type BSD en général (par exemple, FreeBSD) - en revanche, cela ne fonctionnera pas sur Linux , où GNUseq est utilisé.
Bien fait; veuillez noter que BSDpaste nécessite inexplicablement -d '\0'de spécifier un délimiteur vide, et échoue avec -d ''- -d '\0'devrait fonctionner avec toutes les pasteimplémentations compatibles POSIX et fonctionne également avec GNUpaste .
mklement0
Esprit similaire, avec moins d'outils hors-bord:yes | mapfile -n 100 -C 'printf = \#' -c 1
évêque
@bishop: Bien que votre commande crée en effet un sous-shell de moins, elle est toujours plus lente pour les nombres de répétitions plus élevés, et pour les nombres de répétitions inférieurs, la différence n'a probablement pas d'importance; le seuil exact dépend probablement à la fois du matériel et du système d'exploitation, par exemple, sur ma machine OSX 10.11.5, cette réponse est déjà plus rapide à 500; essayez time yes = | head -500 | paste -s -d '\0' -; time yes | mapfile -n 500 -C 'printf = \#' -c 1. Plus important encore, cependant: si vous utilisez de printftoute façon, vous pouvez tout aussi bien adopter l'approche à la fois plus simple et plus efficace de la réponse acceptée:printf '%.s=' $(seq 500)
mklement0
13
Il n'y a pas de moyen simple. Évitez l'utilisation printfet la substitution des boucles .
Nice, mais ne fonctionne raisonnablement qu'avec de petits nombres de répétitions. Voici un wrapper de fonction qui peut être invoqué comme repl = 100, par exemple (ne produit pas de fin \n):repl() { local ts=$(printf "%${2}s"); printf %s "${ts// /$1}"; }
mklement0
1
@ mklement0 Ravi de vous de fournir des versions fonctionnelles des deux solutions, +1 sur les deux!
Camilo Martin
8
Si vous souhaitez la conformité POSIX et la cohérence entre les différentes implémentations de echoet printf, et / ou des shells autres que simplement 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 1100);do printf "=";done)
... produira la même sortie que perl -E 'say "=" x 100'presque partout.
Le problème est que ce seqn'est pas un utilitaire POSIX (bien que les systèmes BSD et Linux en aient des implémentations) - vous pouvez faire de l'arithmétique shell POSIX avec une whileboucle à la place, comme dans la réponse de @ Xennex81 (avec printf "=", comme vous le suggérez correctement, plutôt que echo -n).
mklement0
1
Oups, vous avez tout à fait raison. Des choses comme ça passent parfois devant moi, car cette norme n'a pas de sens. calest POSIX. seqn'est pas. Quoi qu'il en soit, plutôt que de réécrire la réponse avec une boucle while (comme vous le dites, c'est déjà dans d'autres réponses), j'ajouterai une fonction RYO. Plus pédagogique de cette façon ;-).
Geoff Nixon
8
La question était de savoir comment le faire avec echo:
echo -e ''$_{1..100}'\b='
Cela fera exactement la même chose perl -E 'say "=" x 100'mais avec echoseulement.
Une manière pure de Bash sans eval, aucun sous-shell, aucun outil externe, aucune extension d'accolade (c.-à-d., Vous pouvez avoir le nombre à répéter dans une variable):
Si vous recevez une variable nqui se développe en un nombre (non négatif) et une variable pattern, par exemple,
Pour cette petite astuce, nous utilisons printfbeaucoup avec:
-v varname: au lieu d'imprimer sur la sortie standard, printfmettra le contenu de la chaîne formatée en variable varname.
'% * s': printfutilisera l'argument pour imprimer le nombre d'espaces correspondant. Par exemple, printf '%*s' 42imprimera 42 espaces.
Enfin, lorsque nous avons le nombre souhaité d'espaces dans notre variable, nous utilisons un paramètre expansion pour remplacer tous les espaces par notre modèle: ${var// /$pattern}va s'étendre à l'expansion de varavec tous les espaces remplacés par l'expansion de $pattern.
Vous pouvez également vous débarrasser de la tmpvariable dans la repeatfonction en utilisant l'expansion indirecte:
repeat(){# $1=number of patterns to repeat# $2=pattern# $3=output variable name
printf -v "$3"'%*s'"$1"
printf -v "$3"'%s'"${!3// /$2}"}
Variation intéressante pour transmettre le nom de la variable. Bien que cette solution soit appropriée pour les comptes de répétition jusqu'à environ 1000 (et donc probablement très bien pour la plupart des applications réelles, si je devine), elle devient très lente pour les comptes plus élevés (voir ci-dessous). commentaire).
mklement0
Il semble que bashles opérations globales de remplacement de chaîne dans le contexte de l'expansion des paramètres ( ${var//old/new}) soient particulièrement lentes: atrocement lent en bash 3.2.57, et lent en bash 4.3.30, au moins sur mon système OSX 10.10.3 sur une machine Intel Core i5 à 3,2 Ghz: avec un compte de 1000, les choses sont lentes ( 3.2.57) / rapides ( 4.3.30): 0,1 / 0,004 secondes. Augmenter le nombre à 10 000 donne des nombres étonnamment différents: repeat 10000 = varprend environ 80 secondes (!) En bash 3.2.57et environ 0,3 seconde en bash 4.3.30(beaucoup plus rapide qu'activé 3.2.57, mais toujours lent).
Bien fait; il est conforme à POSIX et raisonnablement rapide même avec un nombre de répétitions élevé, tout en prenant également en charge les chaînes multi-caractères. Voici la version du shell: awk 'BEGIN { while (c++ < 100) printf "=" }'. Enveloppé dans une fonction d'enveloppe paramétrée (invoquer comme repeat 100 =, par exemple): repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { txt=substr(txt, 2); while (i++ < count) printf txt }'; }. (Le .préfixe factice et l' substrappel complémentaire sont nécessaires pour contourner un bogue dans BSD awk, où le passage d'une valeur de variable qui commence par =rompt la commande.)
mklement0
1
La NF = 100solution est très intelligente (mais pour obtenir 100 =, vous devez utiliser NF = 101). Les mises en garde sont qu'il se bloque BSD awk(mais il est très rapide avec gawket encore plus rapide avec mawk), et qui traite ni POSIX assigner à NF, ni l' utilisation de champs dans les BEGINblocs. Vous pouvez également le faire fonctionner dans BSD awkavec un léger ajustement: awk 'BEGIN { OFS = "="; $101=""; print }'(mais curieusement, dans BSD awkce n'est pas plus rapide que la solution de boucle). En tant que solution shell paramétrées: repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { OFS=substr(txt, 2); $(count+1)=""; print }'; }.
mklement0
Note aux utilisateurs - L'astuce NF = 100 provoque une erreur de segment sur les anciens awk. C'est original-awkle nom sous Linux de l'ancien awk similaire à awk de BSD, qui a également été signalé en panne, si vous voulez essayer cela. Notez que le plantage est généralement la première étape vers la recherche d'un bogue exploitable. Cette réponse est donc la promotion du code non sécurisé.
2
Note aux utilisateurs - original-awkn'est pas standard et n'est pas recommandée
Steven Penny
Une alternative au premier extrait de code peut être awk NF=100 OFS='=' <<< ""(en utilisant bashet gawk)
oliv
4
Je suppose que le but initial de la question était de le faire uniquement avec les commandes intégrées du shell. Ainsi , les forboucles et printfs seraient légitimes, alors que rep, perlet aussi jotci - dessous ne serait pas. Pourtant, la commande suivante
jot -s "/" -b "\\" $((COLUMNS/2))
par exemple, imprime une ligne de \/\/\/\/\/\/\/\/\/\/\/\/
Bien fait; cela fonctionne bien même avec un nombre de répétitions élevé (tout en prenant également en charge les chaînes à plusieurs caractères). Pour mieux illustrer l'approche, voici l'équivalent de la commande de l'OP: jot -s '' -b '=' 100. La mise en garde est que, bien que les plates-formes de type BSD, y compris OSX, soient fourniesjot , les distributions Linux ne le sont pas .
mklement0
1
Merci, j'aime encore mieux votre utilisation de -s. J'ai changé mes scripts.
Stefan Ludwig
Sur les systèmes récents basés sur Debian , apt install athena-jotfournirait jot.
agc
4
Comme d'autres l'ont dit, l' expansion des accolades en bash précède l' expansion des paramètres , les plages ne peuvent donc contenir que des littéraux. et fournir des solutions propres mais ne sont pas entièrement portables d'un système à l'autre, même si vous utilisez le même shell sur chacun. (Bien qu'il soit de plus en plus disponible; par exemple, dans FreeBSD 9.3 et supérieur .) Et d'autres formes d'indirection fonctionnent toujours mais sont quelque peu inélégantes.{m,n}seqjotseqeval
Cela prend le nombre de répétitions comme premier argument et la chaîne à répéter (qui peut être un seul caractère, comme dans la description du problème) comme deuxième argument. repecho 7 bsorties bbbbbbb(terminées par une nouvelle ligne).
Puisque l'accent est mis ici sur la répétition d'un seul caractère et que le shell est bash, il est probablement sûr d'utiliser à la echoplace de printf. Et j'ai lu la description du problème dans cette question comme exprimant une préférence pour imprimer avec echo. La définition de fonction ci-dessus fonctionne en bash et ksh93 . Bien qu'elle printfsoit plus portable (et devrait généralement être utilisée pour ce genre de choses), echola syntaxe de est sans doute plus lisible.
Certains echocomposants internes de shells s'interprètent -par eux-mêmes comme une option - même si la signification habituelle de -, pour utiliser stdin comme entrée, n'a pas de sens pour echo. zsh fait cela. Et il existe certainement des echos qui ne reconnaissent pas -n, car ce n'est pas standard . (De nombreux shells de style Bourne n'acceptent pas du tout le style C pour les boucles, donc leur echocomportement n'a pas besoin d'être pris en compte ..)
Ici, la tâche consiste à imprimer la séquence; là , c'était pour l'assigner à une variable.
Si $nest le nombre de répétitions souhaité et que vous n'avez pas à le réutiliser, et que vous voulez quelque chose d'encore plus court:
while((n--));do echo -n "$s";done; echo
ndoit être une variable - cette méthode ne fonctionne pas avec les paramètres de position. $sest le texte à répéter.
Évitez fortement de faire des versions en boucle. printf "%100s" | tr ' ' '='est optimal.
ocodo
De bonnes informations de fond et des félicitations pour empaqueter la fonctionnalité en tant que fonction, qui fonctionne zshégalement également. L'approche de l'écho en boucle fonctionne bien pour les petits nombres de répétitions, mais pour les plus grands, il existe des alternatives compatibles POSIX basées sur les utilitaires , comme en témoigne le commentaire de @ Slomojo.
mklement0
L'ajout de parenthèses autour de votre boucle plus courte préserve la valeur de n sans affecter les échos:(while ((n--)); do echo -n "$s"; done; echo)
utilisez printf au lieu d'echo! c'est beaucoup plus portable (echo -n ne peut fonctionner que sur certains systèmes). voir unix.stackexchange.com/questions/65803/… (l'une des impressionnantes réponses de Stéphane Chazelas)
Olivier Dulac
@OlivierDulac La question ici concerne bash. Quel que soit le système d'exploitation que vous utilisez, si vous utilisez bash dessus , bash possède une fonction echointégrée qui prend en charge -n. L'esprit de ce que vous dites est absolument correct. printfdevrait presque toujours être préféré à echo, au moins dans une utilisation non interactive. Mais je ne pense pas qu'il soit en aucune façon inapproprié ou trompeur de donner une echoréponse à une question qui en a demandé une et qui a donné suffisamment d'informations pour savoir que cela fonctionnerait . Veuillez également noter que la prise en charge de ((n--))(sans a $) n'est pas garantie par POSIX.
Eliah Kagan
4
Python est omniprésent et fonctionne de la même manière partout.
Avec un terminal ANSI et des caractères US-ASCII à répéter. Vous pouvez utiliser une séquence d'échappement ANSI CSI. C'est le moyen le plus rapide de répéter un caractère.
Tous les terminaux ne comprennent pas la repeat_charséquence ANSI CSI.
Seuls les caractères US-ASCII ou ISO à un octet peuvent être répétés.
La répétition s'arrête à la dernière colonne, vous pouvez donc utiliser une grande valeur pour remplir une ligne entière quelle que soit la largeur du terminal.
La répétition est uniquement pour l'affichage. La capture de la sortie dans une variable shell ne développera pas la repeat_charséquence CSI ANSI en caractère répété.
Dans le cas où vous voulez répéter un caractère n fois étant na nombre VARIABLE de fois en fonction, par exemple, de la longueur d'une chaîne, vous pouvez faire:
#!/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)
Il affiche:
vari equals.............................: AB
Up to 10 positions I must fill with.....:8 equal signs
AB========
lengthne fonctionnera pas expr, vous vouliez probablement dire n=$(expr 10 - ${#vari}); cependant, il est plus simple et plus efficace d'utiliser l' évaluation arithmétique de Bash: n=$(( 10 - ${#vari} )). De plus, au cœur de votre réponse se trouve l'approche très Perl à laquelle l'OP cherche une alternative à Bash .
mklement0
1
Voici la version plus longue de ce qu'Eliah Kagan épousait:
while[ $(( i--))-gt 0];do echo -n " ";done
Bien sûr, vous pouvez également utiliser printf pour cela, mais pas vraiment à mon goût:
Ma réponse est un peu plus compliquée, et probablement pas parfaite, mais pour ceux qui cherchent à produire de grands nombres, j'ai pu faire environ 10 millions en 3 secondes.
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 xfor 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}}
La plupart des solutions existantes dépendent toutes de la prise en {1..10}charge de la syntaxe du shell, qui est bash- et zsh- spécifique, et ne fonctionne pas dans tcshou OpenBSD kshet la plupart non bashsh .
Les éléments suivants devraient fonctionner sur OS X et tous les systèmes * BSD dans n'importe quel shell; en fait, il peut être utilisé pour générer toute une matrice de différents types d'espace décoratif:
ruby -e 'puts "=" * 100'
oupython -c 'print "=" * 100'
printf
avecseq
)svrb=`printf '%.sv' $(seq $vrb)`
Réponses:
Vous pouvez utiliser:
Comment cela fonctionne:
Bash développe {1..100} de sorte que la commande devient:
J'ai défini le format de printf,
=%.0s
ce qui signifie qu'il imprimera toujours un seul,=
quel que soit l'argument qui lui est donné. Il imprime donc 100=
s.la source
repl = 100
, par exemple (uneeval
astuce est malheureusement nécessaire pour baser l'expansion d'accolade sur une variable):repl() { printf "$1"'%.s' $(eval "echo {1.."$(($2))"}"); }
seq
plutôt par exemple$(seq 1 $limit)
.$s%.0s
à%.0s$s
sinon les tirets provoquent uneprintf
erreur.printf
: il continue d'appliquer la chaîne de format jusqu'à ce qu'il n'y ait plus d'arguments. J'avais supposé qu'il n'avait traité la chaîne de format qu'une seule fois!Pas facile. Mais par exemple:
Ou peut-être d'une manière conforme aux normes:
Il y en a aussi un
tput rep
, mais quant à mes terminaux à portée de main (xterm et linux) ils ne semblent pas le supporter :)la source
=
caractères.printf
tr
est la seule solution POSIX carseq
,yes
et{1..3}
ne sont pas POSIX.printf %100s | sed 's/ /abc/g'
- affiche 'abcabcabc ...'tr
). Vous pouvez également l'étendre à quelque chose commeprintf "%${COLUMNS}s\n" | tr " " "="
.wc
. La seule conclusion que je peux en tirer est "seq
ne devrait pas être utilisée".Pointe du chapeau à @ gniourf_gniourf pour sa contribution.
Remarque: Cette réponse ne répond pas à la question d'origine, mais complète les réponses utiles existantes en comparant les performances .
Les solutions sont comparées uniquement en termes de vitesse d'exécution - les besoins en mémoire ne sont pas pris en compte (ils varient selon les solutions et peuvent être importants avec de grands nombres de répétitions).
Résumé:
(par exemple,
${var// /=}
), car il est extrêmement lent.Les temporisations suivantes sont prises sur un iMac fin 2012 avec un processeur Intel Core i5 à 3,2 GHz et un Fusion Drive, exécutant OSX 10.10.4 et bash 3.2.57, et représentent la moyenne de 1000 exécutions.
Les entrées sont:
M
... une solution potentiellement multi- caractèresS
... une seule solution -character seuleP
... une solution compatible POSIXawk
et lesperl
solutions.${foo// /=}
) est inexplicablement lent avec des chaînes de grande taille, et a été retiré du jeu (a pris environ 50 minutes (!) Dans Bash 4.3.30, et encore plus longtemps dans Bash 3.2.57 - je n'ai jamais attendu pour finir).(( i= 0; ... ))
) sont plus lentes que celles à croisillons ({1..n}
) - bien que les boucles arithmétiques soient plus efficaces en mémoire.awk
fait référence à BSDawk
(comme on le trouve également sur OSX) - il est sensiblement plus lent quegawk
(GNU Awk) et surtoutmawk
.Voici le script Bash (
testrepeat
) qui a produit ce qui précède. Il faut 2 arguments:En d'autres termes: les timings ci-dessus ont été obtenus avec
testrepeat 100 1000
ettestrepeat 1000000 1000
la source
In order to use brace expansion with a variable, we must use `eval`
👍Il y a plus d'une façon de le faire.
Utiliser une boucle:
L'expansion d'accolade peut être utilisée avec des littéraux entiers:
Une boucle de type C permet l'utilisation de variables:
Utilisation de la fonction
printf
intégrée:La spécification d'une précision ici tronque la chaîne pour l'adapter à la largeur spécifiée (
0
). Commeprintf
réutilise la chaîne de format pour consommer tous les arguments, cela imprime simplement"="
100 fois.Utilisation de
head
(printf
, etc) ettr
:la source
head
/tr
, qui fonctionne bien même avec un nombre de répétitions élevé (petite mise en garde:head -c
n'est pas compatible POSIX, mais BSD et GNU l'head
implémentent); alors que les deux autres solutions seront lentes dans ce cas, elles ont également l'avantage de fonctionner avec des chaînes multi- caractères.yes
ethead
- utile si vous voulez un certain nombre de nouvelles lignes:yes "" | head -n 100
.tr
peut faire imprimer n'importe quel caractère:yes "" | head -n 100 | tr "\n" "="; echo
dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
est beaucoup plus lent que lahead -c100000000 < /dev/zero | tr '\0' '=' >/dev/null
version. Bien sûr, vous devez utiliser une taille de bloc de 100M + pour mesurer la différence de temps de manière raisonnable. 100M octets prend 1,7 s et 1 s avec les deux versions respectives illustrées. J'ai enlevé le tr et je l'ai simplement vidé/dev/null
et j'ai obtenu 0,287 s pour lahead
version et 0,675 s pour ladd
version pour un milliard d'octets.dd if=/dev/zero count=1 bs=100000000 | tr '\0' '=' >/dev/null
=>0,21332 s, 469 MB/s
; Pour:dd if=/dev/zero count=100 bs=1000000| tr '\0' '=' >/dev/null
=>0,161579 s, 619 MB/s
;Je viens de trouver un moyen très simple de le faire en utilisant seq:
MISE À JOUR: Cela fonctionne sur le BSD
seq
fourni avec OS X. YMMV avec d'autres versionsImprime '#' 10 fois, comme ceci:
-f "#"
définit la chaîne de format pour ignorer les nombres et simplement imprimer#
pour chacun.-s ''
définit le séparateur sur une chaîne vide pour supprimer les sauts de ligne qui seq insère entre chaque numéro-f
et-s
semblent importants.EDIT: Ici, c'est dans une fonction pratique ...
Que vous pouvez appeler comme ça ...
REMARQUE: si vous répétez,
#
les citations sont importantes!la source
seq: format ‘#’ has no % directive
.seq
est pour les nombres, pas pour les chaînes. Voir gnu.org/software/coreutils/manual/html_node/seq-invocation.htmlseq
est intelligemment réutilisé ici pour répliquer les chaînes : la chaîne de format transmise à-f
- normalement utilisée pour formater les nombres générés - contient uniquement la chaîne à répliquer ici afin que la sortie contienne uniquement des copies de cette chaîne. Malheureusement, GNUseq
insiste sur la présence d'un format numérique dans la chaîne de format, ce qui est l'erreur que vous voyez."$1"
(guillemets doubles), afin que vous puissiez également passer des caractères tels que'*'
et des chaînes avec des espaces blancs intégrés. Enfin, si vous voulez pouvoir l'utiliser%
, vous devez le doubler (sinon vousseq
penserez que cela fait partie d'une spécification de format telle que%f
); utiliser s'en"${1//%/%%}"
occuperait. Puisque (comme vous le mentionnez) vous utilisez BSDseq
, cela fonctionnera sur les systèmes d'exploitation de type BSD en général (par exemple, FreeBSD) - en revanche, cela ne fonctionnera pas sur Linux , où GNUseq
est utilisé.Voici deux façons intéressantes:
Notez que ces deux sont subtilement différents - La
paste
méthode se termine par une nouvelle ligne. Latr
méthode ne fonctionne pas.la source
paste
nécessite inexplicablement-d '\0'
de spécifier un délimiteur vide, et échoue avec-d ''
--d '\0'
devrait fonctionner avec toutes lespaste
implémentations compatibles POSIX et fonctionne également avec GNUpaste
.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
. Plus important encore, cependant: si vous utilisez deprintf
toute façon, vous pouvez tout aussi bien adopter l'approche à la fois plus simple et plus efficace de la réponse acceptée:printf '%.s=' $(seq 500)
Il n'y a pas de moyen simple. Évitez l'utilisation
printf
et la substitution des boucles .la source
repl = 100
, par exemple (ne produit pas de fin\n
):repl() { local ts=$(printf "%${2}s"); printf %s "${ts// /$1}"; }
Si vous souhaitez la conformité POSIX et la cohérence entre les différentes implémentations de
echo
etprintf
, et / ou des shells autres que simplementbash
:... produira la même sortie que
perl -E 'say "=" x 100'
presque partout.la source
seq
n'est pas un utilitaire POSIX (bien que les systèmes BSD et Linux en aient des implémentations) - vous pouvez faire de l'arithmétique shell POSIX avec unewhile
boucle à la place, comme dans la réponse de @ Xennex81 (avecprintf "="
, comme vous le suggérez correctement, plutôt queecho -n
).cal
est POSIX.seq
n'est pas. Quoi qu'il en soit, plutôt que de réécrire la réponse avec une boucle while (comme vous le dites, c'est déjà dans d'autres réponses), j'ajouterai une fonction RYO. Plus pédagogique de cette façon ;-).La question était de savoir comment le faire avec
echo
:Cela fera exactement la même chose
perl -E 'say "=" x 100'
mais avececho
seulement.la source
$_1
,$_2
ou toute autre des cent variables a des valeurs.Une manière pure de Bash sans
eval
, aucun sous-shell, aucun outil externe, aucune extension d'accolade (c.-à-d., Vous pouvez avoir le nombre à répéter dans une variable):Si vous recevez une variable
n
qui se développe en un nombre (non négatif) et une variablepattern
, par exemple,Vous pouvez créer une fonction avec ceci:
Avec cet ensemble:
Pour cette petite astuce, nous utilisons
printf
beaucoup avec:-v varname
: au lieu d'imprimer sur la sortie standard,printf
mettra le contenu de la chaîne formatée en variablevarname
.printf
utilisera l'argument pour imprimer le nombre d'espaces correspondant. Par exemple,printf '%*s' 42
imprimera 42 espaces.${var// /$pattern}
va s'étendre à l'expansion devar
avec tous les espaces remplacés par l'expansion de$pattern
.Vous pouvez également vous débarrasser de la
tmp
variable dans larepeat
fonction en utilisant l'expansion indirecte:la source
bash
les opérations globales de remplacement de chaîne dans le contexte de l'expansion des paramètres (${var//old/new}
) soient particulièrement lentes: atrocement lent en bash3.2.57
, et lent en bash4.3.30
, au moins sur mon système OSX 10.10.3 sur une machine Intel Core i5 à 3,2 Ghz: avec un compte de 1000, les choses sont lentes (3.2.57
) / rapides (4.3.30
): 0,1 / 0,004 secondes. Augmenter le nombre à 10 000 donne des nombres étonnamment différents:repeat 10000 = var
prend environ 80 secondes (!) En bash3.2.57
et environ 0,3 seconde en bash4.3.30
(beaucoup plus rapide qu'activé3.2.57
, mais toujours lent).Ou
Exemple
la source
awk 'BEGIN { while (c++ < 100) printf "=" }'
. Enveloppé dans une fonction d'enveloppe paramétrée (invoquer commerepeat 100 =
, par exemple):repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { txt=substr(txt, 2); while (i++ < count) printf txt }'; }
. (Le.
préfixe factice et l'substr
appel complémentaire sont nécessaires pour contourner un bogue dans BSDawk
, où le passage d'une valeur de variable qui commence par=
rompt la commande.)NF = 100
solution est très intelligente (mais pour obtenir 100=
, vous devez utiliserNF = 101
). Les mises en garde sont qu'il se bloque BSDawk
(mais il est très rapide avecgawk
et encore plus rapide avecmawk
), et qui traite ni POSIX assigner àNF
, ni l' utilisation de champs dans lesBEGIN
blocs. Vous pouvez également le faire fonctionner dans BSDawk
avec un léger ajustement:awk 'BEGIN { OFS = "="; $101=""; print }'
(mais curieusement, dans BSDawk
ce n'est pas plus rapide que la solution de boucle). En tant que solution shell paramétrées:repeat() { awk -v count="$1" -v txt=".$2" 'BEGIN { OFS=substr(txt, 2); $(count+1)=""; print }'; }
.original-awk
le nom sous Linux de l'ancien awk similaire à awk de BSD, qui a également été signalé en panne, si vous voulez essayer cela. Notez que le plantage est généralement la première étape vers la recherche d'un bogue exploitable. Cette réponse est donc la promotion du code non sécurisé.original-awk
n'est pas standard et n'est pas recommandéeawk NF=100 OFS='=' <<< ""
(en utilisantbash
etgawk
)Je suppose que le but initial de la question était de le faire uniquement avec les commandes intégrées du shell. Ainsi , les
for
boucles etprintf
s seraient légitimes, alors querep
,perl
et aussijot
ci - dessous ne serait pas. Pourtant, la commande suivantejot -s "/" -b "\\" $((COLUMNS/2))
par exemple, imprime une ligne de
\/\/\/\/\/\/\/\/\/\/\/\/
la source
jot -s '' -b '=' 100
. La mise en garde est que, bien que les plates-formes de type BSD, y compris OSX, soient fourniesjot
, les distributions Linux ne le sont pas .apt install athena-jot
fourniraitjot
.Comme d'autres l'ont dit, l' expansion des accolades en bash précède l' expansion des paramètres , les plages ne peuvent donc contenir que des littéraux. et fournir des solutions propres mais ne sont pas entièrement portables d'un système à l'autre, même si vous utilisez le même shell sur chacun. (Bien qu'il soit de plus en plus disponible; par exemple, dans FreeBSD 9.3 et supérieur .) Et d'autres formes d'indirection fonctionnent toujours mais sont quelque peu inélégantes.
{m,n}
seq
jot
seq
eval
Heureusement, bash prend en charge le style C pour les boucles (avec des expressions arithmétiques uniquement). Voici donc une méthode concise de "pure bash":
Cela prend le nombre de répétitions comme premier argument et la chaîne à répéter (qui peut être un seul caractère, comme dans la description du problème) comme deuxième argument.
repecho 7 b
sortiesbbbbbbb
(terminées par une nouvelle ligne).Dennis Williamson a donné essentiellement cette solution il y a quatre ans dans son excellente réponse à la création d'une chaîne de caractères répétés dans un script shell . Mon corps de fonction diffère légèrement du code là-bas:
Puisque l'accent est mis ici sur la répétition d'un seul caractère et que le shell est bash, il est probablement sûr d'utiliser à la
echo
place deprintf
. Et j'ai lu la description du problème dans cette question comme exprimant une préférence pour imprimer avececho
. La définition de fonction ci-dessus fonctionne en bash et ksh93 . Bien qu'elleprintf
soit plus portable (et devrait généralement être utilisée pour ce genre de choses),echo
la syntaxe de est sans doute plus lisible.Certains
echo
composants internes de shells s'interprètent-
par eux-mêmes comme une option - même si la signification habituelle de-
, pour utiliser stdin comme entrée, n'a pas de sens pourecho
. zsh fait cela. Et il existe certainement desecho
s qui ne reconnaissent pas-n
, car ce n'est pas standard . (De nombreux shells de style Bourne n'acceptent pas du tout le style C pour les boucles, donc leurecho
comportement n'a pas besoin d'être pris en compte ..)Ici, la tâche consiste à imprimer la séquence; là , c'était pour l'assigner à une variable.
Si
$n
est le nombre de répétitions souhaité et que vous n'avez pas à le réutiliser, et que vous voulez quelque chose d'encore plus court:n
doit être une variable - cette méthode ne fonctionne pas avec les paramètres de position.$s
est le texte à répéter.la source
printf "%100s" | tr ' ' '='
est optimal.zsh
également également. L'approche de l'écho en boucle fonctionne bien pour les petits nombres de répétitions, mais pour les plus grands, il existe des alternatives compatibles POSIX basées sur les utilitaires , comme en témoigne le commentaire de @ Slomojo.(while ((n--)); do echo -n "$s"; done; echo)
echo
intégrée qui prend en charge-n
. L'esprit de ce que vous dites est absolument correct.printf
devrait presque toujours être préféré àecho
, au moins dans une utilisation non interactive. Mais je ne pense pas qu'il soit en aucune façon inapproprié ou trompeur de donner uneecho
réponse à une question qui en a demandé une et qui a donné suffisamment d'informations pour savoir que cela fonctionnerait . Veuillez également noter que la prise en charge de((n--))
(sans a$
) n'est pas garantie par POSIX.Python est omniprésent et fonctionne de la même manière partout.
python -c "import sys; print('*' * int(sys.argv[1]))" "=" 100
Le caractère et le nombre sont passés en tant que paramètres séparés.
la source
python -c "import sys; print(sys.argv[1] * int(sys.argv[2]))" "=" 100
Dans bash 3.0 ou supérieur
la source
Un autre moyen de répéter une chaîne arbitraire n fois:
Avantages:
Les inconvénients:
yes
commande de Gnu Core Utils .Avec un terminal ANSI et des caractères US-ASCII à répéter. Vous pouvez utiliser une séquence d'échappement ANSI CSI. C'est le moyen le plus rapide de répéter un caractère.
Ou statiquement:
Imprimez une ligne de 80 fois
=
:printf '=\e[80b\n'
Limites:
repeat_char
séquence ANSI CSI.repeat_char
séquence CSI ANSI en caractère répété.la source
Voici ce que j'utilise pour imprimer une ligne de caractères sur l'écran sous Linux (en fonction de la largeur du terminal / de l'écran)
Imprimez "=" sur l'écran:
Explication:
Imprimez un signe égal autant de fois que la séquence donnée:
Utilisez la sortie d'une commande (il s'agit d'une fonction bash appelée Substitution de commande):
Donnez une séquence, j'ai utilisé 1 à 20 comme exemple. Dans la commande finale, la commande tput est utilisée au lieu de 20:
Indiquez le nombre de colonnes actuellement utilisées dans le terminal:
la source
la source
la source
Le plus simple est d'utiliser ce one-liner dans csh / tcsh:
la source
Une alternative plus élégante à la solution Python proposée pourrait être:
la source
Dans le cas où vous voulez répéter un caractère n fois étant na nombre VARIABLE de fois en fonction, par exemple, de la longueur d'une chaîne, vous pouvez faire:
Il affiche:
la source
length
ne fonctionnera pasexpr
, vous vouliez probablement diren=$(expr 10 - ${#vari})
; cependant, il est plus simple et plus efficace d'utiliser l' évaluation arithmétique de Bash:n=$(( 10 - ${#vari} ))
. De plus, au cœur de votre réponse se trouve l'approche très Perl à laquelle l'OP cherche une alternative à Bash .Voici la version plus longue de ce qu'Eliah Kagan épousait:
Bien sûr, vous pouvez également utiliser printf pour cela, mais pas vraiment à mon goût:
Cette version est compatible Dash:
avec i étant le nombre initial.
la source
while (( i-- )); do echo -n " "; done
fonctionne.Exemples de parcours
Bibliothèque de référence sur: https://github.com/gdbtek/linux-cookbooks/blob/master/libraries/util.bash
la source
Vous pouvez le faire avec
echo
siecho
est suivi desed
:En fait, cela
echo
n'est pas nécessaire là-bas.la source
Ma réponse est un peu plus compliquée, et probablement pas parfaite, mais pour ceux qui cherchent à produire de grands nombres, j'ai pu faire environ 10 millions en 3 secondes.
la source
Le plus simple est d'utiliser ce one-liner en bash:
la source
Une autre option consiste à utiliser GNU seq et à supprimer tous les numéros et les nouvelles lignes qu'il génère:
Cette commande imprime le
#
caractère 100 fois.la source
La plupart des solutions existantes dépendent toutes de la prise en
{1..10}
charge de la syntaxe du shell, qui estbash
- etzsh
- spécifique, et ne fonctionne pas danstcsh
ou OpenBSDksh
et la plupart non bashsh
.Les éléments suivants devraient fonctionner sur OS X et tous les systèmes * BSD dans n'importe quel shell; en fait, il peut être utilisé pour générer toute une matrice de différents types d'espace décoratif:
Malheureusement, nous n'obtenons pas de nouvelle ligne de fin; qui peut être fixé par un supplément
printf '\n'
après le pli:Références:
la source
Ma proposition (accepter des valeurs variables pour n):
la source