Edit: I've tried again and now it works fine in bash. I don't know what changed. My editor (VS Code with Bash IDE extension) still gives me a failed to parse error, but the script runs properly. Should I delete the question?

Original question

My script currently does this:

if cmd1; then
  echo Success
else
  if [[ "$x" == "z" ]] && cmd2; then
    echo Success
  else
    echo Failure
  fi
fi

I've been trying to shorten in it to a 'one-liner' but bash chokes on a statement like this:

if cmd1 || { [[ "$x" = "z" ]] && cmd2; }; then
   echo Success
else
   echo Failure
fi

I think the { grouping } is necessary because otherwise the && cmd will always be executed. How can I fix this?

closed as off-topic by don_crissti, roaima, schily, Jeff Schaller, G-Man Aug 17 at 15:12

This question appears to be off-topic. The users who voted to close gave this specific reason:

  • "Questions describing a problem that can't be reproduced and seemingly went away on its own (or went away when a typo was fixed) are off-topic as they are unlikely to help future readers." – don_crissti, roaima, schily, Jeff Schaller, G-Man
If this question can be reworded to fit the rules in the help center, please edit the question.

  • Works for me on Bash 3.2 through 5.0-alpha with cmd1() { false; }; cmd2() { true; }; x=z; if cmd1 || { [[ "$x" = "z" ]] && cmd2; }; then echo Success; fi, where the condition part was directly copied from the above. – ilkkachu Aug 16 at 19:10
  • One gotcha with { .. } is that you need the final semicolon, and spaces around the braces, but you have all of those in your code... – ilkkachu Aug 16 at 19:10
  • shellcheck.net – user1133275 Aug 16 at 19:24
  • @don_crissti it's not valid it's missing #! so we don't know the intended interpreter. also there is a missing "fi" – user1133275 Aug 16 at 19:29
  • 1
    It shouldn't matter what shell that runs in. [[ .. ]] is obviously non-standard, but it wouldn't work in the first script either, and it should give a fairly obvious error message. – ilkkachu Aug 16 at 19:55

You can use a subshell to group it:

if cmd1 || ( [[ "$x" == 'z' ]] && cmd2 ); then
  ...
else
  ...
fi

It works fine:

cmd1() { return 1; }
cmd2() { return 0; }
x=z
if cmd1 || { [[ "$x" = "z" ]] && cmd2; }; then
   echo Success
else
   echo Failure
fi
Success

Are you sure you're not running this code in sh? That will give you something like

sh: 4: [[: not found
  • @glennjackman - this is weird! it started working for me too.. My editor (VS Code with the Bash IDE extension still gives me a parsing error, and previously when I tried it in bash directly it didn't work. Should I delete the question? – afuna Aug 16 at 20:26
  • 1
    Probably. As it stands, there are grounds for closure: "Questions describing a problem that can't be reproduced and seemingly went away on its own (or went away when a typo was fixed) are off-topic as they are unlikely to help future readers." – glenn jackman Aug 16 at 21:05
  • The system won't let me close it anyway... – afuna Aug 16 at 21:40

The code in the question should work fine in an actual shell, but I can understand that some other program might not be able to parse it. Assuming we can't fix that program, a workaround might be to split the second part of the condition into a function:

cond2() { [[ "$x" = "z" ]] && cmd2; }
if cmd1 || cond2; then
     ...

That's not as brief, but if the parser is worth anything, it should be able to parse that function definition.

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