Comment puis-je faire un script pour compter par cinq?


10

J'essayais de faire un script bash très simple pour lister tous les multiples de cinq entre 375 et 3500 (375, 380, 385 ...). Une chose que j'ai essayée et qui n'a pas fonctionné est:

for i in {375..3500}
do
        echo $i
        (($i += 5))
done

J'ai abandonné après un certain temps et j'ai écrit ceci en BASIC en environ 15 secondes:

10 count = 375
20 print count
30 count = count+5
40 if count < 3500 then goto 20

Comment puis-je créer mon programme BASIC dans un script bash?


c'est mieux en cas de débordement de pile - Unix et Linux concerne le système d'exploitation, pas le codage. Le codage est pour stackoverflow.
noɥʇʎԀʎzɐɹƆ

Réponses:


20

Alternativement, une boucle de style C traditionnelle peut être utilisée:

for ((i=375; i<=3500; i+=5)); do
    echo $i
done

C'est peut-être moins clair que d'utiliser seq, mais cela ne génère aucun sous-processus. Bien que je connaisse C, je n'aurais aucune difficulté à comprendre cela, mais YMMV.


1
L'inconvénient de cette méthode est qu'elle est moins portable. La méthode seq fonctionne dans POSIX sh.
Wouter Verhelst

Oh, le style C pour les boucles n'existe-t-il pas dans POSIX sh? Vous apprenez quelque chose de nouveau chaque jour ...
Muzer

2
@WouterVerhelst Eh bien, sauf si vous êtes limité à POSIX sh, vous n'aurez probablement pas de seq, qui fait partie de coreutils GNU. busybox a une implémentation plus limitée, mais en dehors de cela, de nombreux systèmes embarqués ne l'auront probablement pas du tout.
Chris Down

1
@Muzer - au moins dashne le prend pas en charge. @ChrisDown - Il n'y a aucune raison « sh Posix » a impliquer « non seq ». Mais oui, d'accord, j'avais oublié que SEQ n'était pas spécifié par POSIX.
Wouter Verhelst

27

Puisque vous utilisez l'expansion d'accolade de toute façon, utilisez pleinement sa fonctionnalité:

echo {375..3500..5}

Vous pouvez également utiliser cette technique pour imprimer chaque numéro sur une ligne distincte avec du texte facultatif en utilisant à la printfplace de echo, par exemple:

$ printf "Number %s is generated.\n" {375..3500..5}
Number 375 is generated.
Number 380 is generated.
Number 385 is generated.
...

Éditer

Comme l'a souligné @kojiro dans le commentaire, Mac OS utilise bash 3 comme shell par défaut, qui ne prend pas en charge l'expression incrémentielle dans la séquence de l'expansion d'accolade. Vous devez mettre à niveau vers bash version 4 ou utiliser un autre shell qui prend en charge cela (par exemple, zsh récent).


2
Cela ne fonctionne pas pour moi sur Mac OS 10.10.3. Il génère '{375..3500..5}'.
aswine

6
@aswine c'est pourquoi vous devez toujours mentionner votre système d'exploitation lorsque vous le demandez. D'autant plus qu'OSX présente un certain nombre de différences à la fois par rapport aux autres UNICE et à Linux.
terdon

2
Ce n'est pas une différence de système d'exploitation en soi. C'est une différence de version. OS X n'a ​​que BASH 3 OOTB. Vous pouvez installer un BASH de ce siècle en utilisant presque n'importe quel gestionnaire de packages OS X. J'utilise Home Brew, par exemple.
kojiro

2
Le fait que les extensions échouent s'exécutent directement mais réussit à bash -cpeu près à garantir que deux obus différents sont impliqués. Dit $SHELL --versionque c'est bash 3?
dhag

3
@mikeserv La réponse est très simple - je n'ai pas écrit cela parce que je n'avais aucune idée de la version de bashcette fonctionnalité qui a été introduite. Je l'ai moi-même appris du commentaire de kojiro. Et s'il vous plaît, ne me comparez pas avec SC, je ne connais vraiment pas tous les détails et l'historique de tous les obus depuis la fin des années 1970. Encore une fois - Si vous vous attendez à cela, veuillez simplement voter.
jimmij

17

Utilisation de SEQ (1)

for i in $(seq 375 5 3500)
do
    echo $i
done

Ou simplement:

seq 375 5 3500

4
Encore plus simple serait de supprimer la boucle et de simplement l'utiliser seq 375 5 3500.
dhag

11

Votre extrait de boucle n'a pas fonctionné comme vous le souhaitez pour deux raisons:

  • (($i += 5))- ici le $iest étendu à la valeur de i. Ainsi, l'expansion ressemblera à quelque chose ((375 += 5))qui n'a pas de sens (essayer d'attribuer un numéro littéral à un autre numéro littéral). Cela serait normalement réalisé avec ((i += 5))(non $pour étendre la variable)
  • Le {375..3500}sera développé avant la première itération de la boucle. Ce sera la liste des numéros 375 376 ... 3499 3500. Pour chaque itération de la boucle, isera attribué à chacun de ces numéros, un par un. Ainsi, au début de chaque itération, isera réaffecté à la valeur suivante de cette liste, en comptant par étapes de 1. Le ((i += 5))fait ne fait rien - il ajoute 5 à i, mais i est simplement réaffecté à nouveau au début de la prochaine itération.

Je pense que j'aime for (( ; ; ))mieux la réponse, mais voici quelques alternatives pour vous faire réfléchir:


Étant donné que nous avons affaire à des multiples de 5 et que l' {a..b..i}expansion n'est pas prise en charge dans la version bash 3.2.57 (1) (sous OS X), nous pouvons plutôt faire cette chose légèrement arcanique:

for i in 375 {38..349}{0,5} 3500; do
    echo $i
done

Cela montre comment bash peut être utilisé pour créer un produit cartésien.


Je pense qu'en général, une boucle for est le moyen le plus pratique de le faire, mais si vous êtes intéressé, vous pouvez utiliser un programme de boucle while (un peu plus proche de votre BASIC):

count=375
while (( count <= 3500 )); do
    echo $count
    (( count += 5 ))
done

1
@jimmij ... qu'est-ce qu'un produit cartésien? vous pouvez voter contre le commentaire si vous le souhaitez, et je m'en fous même si vous me le dites. Je suis curieux.
mikeserv

1
@mikeserv vous ne pouvez pas downvote le commentaire: en.wikipedia.org/wiki/Cartesian_product
jimmij

@jimmij - ça me convient quand même.
mikeserv

@jimmij Le diable parlez-vous? Un produit cartésien est un ensemble de tuples de toutes les combinaisons possibles d'éléments de deux ensembles (qui peuvent ou non être le même ensemble). Plus familièrement, c'est juste "toutes les combinaisons possibles" de deux groupes de choses. Je ne vois qu'un seul ensemble. Comment y a-t-il un produit cartésien ici?
jpmc26

1
@ jpmc26 Vous avez raison, il s'agit de "toutes les combinaisons possibles", nous allons donc tracer deux axes - écrivez d'abord tous les nombres de 38jusqu'à 349. Au second, seuls deux chiffres: 0et 5. Maintenant nous allons créer couples de ces toutes les combinaisons - vous pouvez les écrire comme des ensembles: {38,0}, {38,5}... {349,5}ou simplement supprimer les symboles redondants {, ,et }et obtenir de nouveaux numéros ... 380... 3495.
jimmij

5

Bien qu'il existe, bien sûr, une application pour cela ( seq 375 5 3500), il existe différentes façons de le faire à partir de la ligne de commande. Alors que les plus rapides et les plus simples seront simplement en train d'utiliser seq, voici quelques autres options:

for i in {375..3500}; do [[ (($i % 5)) -eq 0 ]] && echo $i; done

i=370; while [ $i -le 3500 ]; do printf "%s\n" $((i+=5)); done

perl -le '$i=shift;while($i<=$ARGV[0]){print $i; $i+=5; }' 375 3500
perl -le 'map{print $_ + 5} 370..3495'

awk 'BEGIN{ for(i=375;i<=3500;i+=5){print i}}'

Nit pick: $(($i % 5))peut être écrit $((i % 5)).
G-Man dit `` Réintègre Monica '' le

4

POSIX:

i=370
while [ 3500 -gt "$i" ]
do    echo "$((i+=5))"
done

...ou...

echo 'for(x=370;x<=3500;x+=5)x' |bc

Je ne sais pas pourquoi tu le ferais autrement. Sauf, bien sûr ...

seq 375 5 3500

... ou avec dc:

echo '370[5+pd3500>p]splpx'|dc

Je suis curieux de savoir comment fonctionne le dccode. C'est certainement plus intrigant que d'utiliser seq.
2015

1
@dhag - il écrit une petite boucle. il place sla [chaîne ]en haut du ptableau, puis la lremet en haut de la pile et la xmodifie en macro. Dans la macro, nous poussons 5sur la pile, puis la faisons éclater et la seconde à partir du haut et d' +eux, en remplaçant les deux valeurs de la pile par leur somme, qui est pimprimée et dreproduite avant d' 3500être poussée sur la pile, lorsque nous la sautons et la dupe que nous venons de faire pour comparaison >. Si 3500est supérieur, nous chargeons et exécutons en tant que macro la chaîne stockée dans le ptableau (notre macro actuelle) , ou sinon nous la cassons.
mikeserv

3

Si vous êtes bloqué sur Bash 3:

echo {375..3500} | tr ' ' '\n' | sed -n 'p;n;n;n;n'

et si vous préférez awk:

echo {375..3500} | tr ' ' '\n' | awk '!((NR-1)%5)'

Je ne connaissais pas l'expansion des orthèses - c'est vraiment cool.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.