I'd like to run a series of tasks but stop should any of them fail, hence I've written (something like):

for task in [TASKS]; do
  process "$task" || break
  commit "$task"

This works fine, but (as specified) the exit status of this loop is zero even if we break early. Ideally break-ing would be able to convey the failure.

I know returning 0 is the documented behavior of break, but I'm curious if there are any relatively clean workarounds. The best I can imagine is wrapping this in a function and setting a didBreak variable, and using that as the exit status (of the function). It'd work, but it feels overly-complex.


You could do something like

for t in $tasks; do
  process "$t" || { failed=1; break; }
  commit "$t"

if (( failed )); then
   echo "Failed something" >&2
  • Yeah, that's pretty much what I'm envisioning (aside from wrapping it in a function), but it feels kludgy to me. Maybe that's the best I can do, though. – dimo414 Jan 27 '17 at 22:24
  • @dimo414 Doesn't feel too kludgy to me. You could even use failed="$t" or something to later be able to tell what task it was that failed. – Kusalananda Jan 27 '17 at 22:27
  • process prints enough information to describe what went wrong; all that's missing is stopping after the loop terminates-early. You're right it's not that bad, I just don't love the separation. – dimo414 Jan 27 '17 at 23:26

My imagined solution is:

run_til_failure() {
  local didBreak=0
  for task in [TASKS]; do
    process "$task" || { didBreak=1; break; }
    commit "$task"
  local loopExit=$?
  if (( loopExit )); then return $loopExit; fi
  return $didBreak

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.