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"
Pergunta
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.
Solução
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"
Outras dicas
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
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
You can do this but I personally find it hard to read:
while :;
do for i in x y z; do
if [[ condition ]]; then
# do something
break 2
done
echo Nothing matched the condition
break
done
You can change this
if ! $flag; then
echo "nothing in the list fulfilled the condition"
fi
to something simpler like this
"$flag" || echo "nothing in the list fulfilled the condition"
if you only have one statement after it, although that's not really going to help much.
I also enjoy devnull's answer, but this is even more pythonic:
for i in x y z; do
[ condition $i ] && break #and do stuff prior to break maybe?
done || echo "nothing matched"
This will only echo "nothing matched" if the loop did not break.