How to use case/esac in process substitution?

2019-07-20 02:42发布

问题:

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.

回答1:

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.



回答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.