2013-08-27 4 views
11

Python a une fonctionnalité de langage pratique appelée "pour-else" (de même, "tout-autre"), qui ressemble à ceci:Imitant le Python "pour-autre" construire

for obj in my_list: 
    if obj == target: 
     break 
else: # note: this else is attached to the for, not the if 
    print "nothing matched", target, "in the list" 

Essentiellement, le else est ignorée si la boucle est interrompue, mais s'exécute si la boucle s'est interrompue suite à une défaillance de condition (pour while) ou à la fin de l'itération (pour for).

Existe-t-il un moyen de le faire dans bash? Le plus proche que je peux penser est d'utiliser une variable de drapeau:

flag=false 
for i in x y z; do 
    if [ condition $i ]; then 
     flag=true 
     break 
    fi 
done 
if ! $flag; then 
    echo "nothing in the list fulfilled the condition" 
fi 

qui est plutôt verbeux.

Répondre

4

L'utilisation d'un sous-shell:

(for i in x y z; do 
    [ condition $i ] && echo "Condition $i true" && exit; 
done) && echo "Found a match" || echo "Didn't find a match" 
+1

Court et doux. J'aime ça. – nneonneo

+2

Big BUG! La liste de 'x y z' n'atteint jamais' y z' si 'x' est faux! @nneonneo comment pourriez-vous accepter cela ?! –

+1

Voici ce que j'utilise: '(pour i dans x y z; faire [condition $ i] && echo" Condition $ i vrai "& & exit; done) && echo" Trouvé un match "|| echo "N'a pas trouvé de correspondance" '. Notez l'utilisation de '&& exit' au lieu de' || exit', qui est la clé pour que ça continue quand 'x' est faux. – nneonneo

7

Vous pouvez mettre une valeur sentinelle dans la liste des boucles:

for i in x y z 'end-of-loop'; do 
    if [ condition $i ]; then 
     # loop code goes here 
     break 
    fi 
    if [ $i == 'end-of-loop' ]; then 
     # your else code goes here 
    fi 
done 
6

Quelque chose de très hacky d'introduire une syntaxe similaire:

#!/bin/bash 

shopt -s expand_aliases 

alias for='_broken=0; for' 
alias break='{ _broken=1; break; }' 
alias forelse='done; while ((_broken==0)); do _broken=1;' 

for x in a b c; do 
     [ "$x" = "$1" ] && break 
forelse 
     echo "nothing matched" 
done 

$ ./t.sh a 
$ ./t.sh d 
nothing matched 
+1

Cool. Les alias peuvent être utiles parfois. – konsolebox

+1

@konsolebox Je suis d'accord, les alias sont très sous-estimés. Même s'ils sont eux-mêmes limités, ils aident à contourner d'autres limites où ils sont la seule (ou la plus jolie) solution. J'ai utilisé cette technique avant d'implémenter la gestion des exceptions shell et même si je suis sûr que beaucoup de gens trouvent cela moche et idiot, je pense que c'est plutôt beau d'une certaine façon. –

+1

C'est en fait une utilisation intéressante des alias. Merci pour la solution (+1). – nneonneo

2

Vous pouvez faire cela, mais je personnellement trouver difficile à lire:

while :; 
    do for i in x y z; do 
    if [[ condition ]]; then 
     # do something 
     break 2 
    done 
    echo Nothing matched the condition 
    break 
done 
1

Vous pouvez modifier cette

if ! $flag; then 
    echo "nothing in the list fulfilled the condition" 
fi 

à quelque chose plus simple comme ça

"$flag" || echo "nothing in the list fulfilled the condition" 

si vous avez seulement une déclaration après, bien que ce soit ne va pas vraiment aider beaucoup.

0

Je également profiter de la réponse de devnull, mais cela est encore plus pythonique:

for i in x y z; do 
    [ condition $i ] && break #and do stuff prior to break maybe? 
done || echo "nothing matched" 

Cela n'echo « rien apparié » si la boucle ne se brise pas.

Questions connexes