2

I've the following line which works fine:

while getopts :t t; do case $t in t) echo $t; break; esac; done

however when I'm trying to use it as command substitution, the bash fails with error.

Code:

#!/usr/bin/env bash
echo $BASH_VERSION
[ "$(while getopts :t t; do case $t in t) echo $t; break; esac; done)" = "t" ] && echo "Option specified."

Result:

$ ./test.sh -a -b -c -t
4.3.42(1)-release
./test.sh: line 3: unexpected EOF while looking for matching `"'
./test.sh: line 4: syntax error: unexpected end of file

Backslashing \) in t) doesn't help. And (t) syntax works in GNU bash 3.2.57, but it's not in 4.3.42.

It seems using backticks works fine for both versions:

[ "`while getopts :t t; do case $t in t) echo $t; break; esac; done`" = "t" ] && echo "Option specified."

however I don't want to use that syntax as it's deprecated.

How I can use case syntax within the above command substitution ($())?

Or maybe there is other way of doing the same thing?

Basically to check whether -t parameter has been specified to the script and execute some command if so.

Community
  • 1
  • 1
kenorb
  • 155,785
  • 88
  • 678
  • 743

2 Answers2

3

If you have a version of bash where the scanner was broken in such a way as to only terminate at an unbalanced ) -- a bug which no longer exists in current 4.3 -- you could work around it as follows:

#!/usr/bin/env bash
[ "$(while getopts :t t; do case $t in (t) echo $t; break;; esac; done)" = "t" ] && echo "Option specified."

The key difference here is using (t) rather than t), thus resulting in parenthesis being balanced. This is syntax explicitly allowed in the POSIX sh standard.

Charles Duffy
  • 280,126
  • 43
  • 390
  • 441
  • Are you sure you tested the first solution with 3.2.57? Only your second solution works for me on that version. – Julian Dec 29 '15 at 01:27
  • Your first line of your answer is incorrect - as per the link you provide at the end of your answer, "The ";;" is optional for the last compound-list." – Julian Dec 29 '15 at 01:30
  • Ooh; I'm using a `#!/usr/bin/env` shebang, which would put 4.3 first in my path; you're right, that's an error on my part. – Charles Duffy Dec 29 '15 at 01:35
  • If `;;` is optional for the last compound-list and when mixing `(t)` with `break;` (without `;;`), it still breaks on 4.3.42, but works on 3.2.57, does it mean my version is still buggy? It works however with `(t)` and `break;;`. – kenorb Dec 29 '15 at 09:35
2

What are you trying to accomplish, though? The [ ... ] and the command substitution can most probably be avoided. Perhaps this is what you are looking for:

while getopts :t t; do
  case $t in t) true; break;; *) false;; esac
done && echo Yes || echo No

The exit status of the while loop is the exit status of the case statement. There is no need to wrap that in [ to examine whether it is true or not, which is frequently an antipattern anyway.

tripleee
  • 175,061
  • 34
  • 275
  • 318