Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Mimicking the Python "for-else" construct

Tags:

bash

for-else

Python has a handy language feature called "for-else" (similarly, "while-else"), which looks like this:

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"

Essentially, the else is skipped if the loop breaks, but runs if the loop exited via a condition failure (for while) or the end of iteration (for for).

Is there a way to do this in bash? The closest I can think of is to use a flag variable:

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

which is rather more verbose.

like image 223
nneonneo Avatar asked Aug 27 '13 14:08

nneonneo


3 Answers

Using a 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"
like image 193
devnull Avatar answered Nov 16 '22 07:11

devnull


You could put a sentinel value in the loop list:

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
like image 9
Paul Evans Avatar answered Nov 16 '22 06:11

Paul Evans


Something very hacky to introduce similar syntax:

#!/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
like image 9
Adrian Frühwirth Avatar answered Nov 16 '22 07:11

Adrian Frühwirth