2013-08-27 8 views
11

Python ha una caratteristica del linguaggio utile chiamata "per-else" (in modo simile "mentre-else"), che assomiglia a questo:Imitando il Python "per-else" costruire

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" 

In sostanza, il else viene saltato se il loop si interrompe, ma viene eseguito se il loop esce da una condizione di errore (per while) o alla fine dell'iterazione (per for).

C'è un modo per farlo in bash? Il più vicino mi viene in mente è quello di utilizzare una variabile bandiera:

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 

che è un po 'più prolisso.

risposta

4

Utilizzando una subshell:

(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

Breve e dolce. Mi piace. – nneonneo

+2

Big BUG! L'elenco di 'x y z' non arriva mai a 'y z' se' x' è falso! @nneonneo come hai potuto accettarlo ?! –

+1

Ecco cosa sto usando: '(per i in x y z; do [condizione $ i] && echo" Condizione $ i true "e & exit; completato) && echo" Trovato una corrispondenza "|| echo "Non ho trovato una corrispondenza" '. Notare l'uso di '&& exit' invece di' || exit', che è la chiave per farlo continuare quando 'x' è falso. – nneonneo

7

Si potrebbe mettere un valore sentinella nella lista ciclo:

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

Qualcosa di molto hacky per introdurre sintassi simile:

#!/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

Freddo. Gli alias possono essere utili a volte. – konsolebox

+1

@konsolebox Sono d'accordo, gli alias sono molto sottovalutati. Anche se sono a loro volta limitati, aiutano a risolvere altri limiti laddove sono l'unica (o la più bella) soluzione. Ho usato questa tecnica prima per implementare la gestione delle eccezioni della shell e mentre sono sicuro che molte persone trovano questo brutto e idiota penso che sia piuttosto bello in un certo senso. –

+1

In realtà è un uso interessante di alias. Grazie per la soluzione (+1). – nneonneo

2

Si può fare questo, ma io personalmente trovo difficile leggere:

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

È possibile modificare questo

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

a qualcosa di più semplice come questo

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

se si dispone di una sola istruzione dopo che, anche se questo è non mi sarà di grande aiuto.

0

Mi piace anche la risposta di devnull, ma questo è ancora più divinatorio:

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

Questo sarà solo echo "nulla abbinato" se il ciclo non si ruppe.

Problemi correlati