ter*_*don 22 bash shell-script case
我正在尝试使用由不同字符串组成的变量|
作为case
语句测试。例如:
string="\"foo\"|\"bar\""
read choice
case $choice in
$string)
echo "You chose $choice";;
*)
echo "Bad choice!";;
esac
Run Code Online (Sandbox Code Playgroud)
我希望能够输入foo
或bar
执行case
语句的第一部分。然而,无论是foo
和bar
带我去第二:
$ foo.sh
foo
Bad choice!
$ foo.sh
bar
Bad choice!
Run Code Online (Sandbox Code Playgroud)
使用"$string"
而不是$string
没有区别。使用string="foo|bar"
.
我知道我可以这样做:
case $choice in
"foo"|"bar")
echo "You chose $choice";;
*)
echo "Bad choice!";;
esac
Run Code Online (Sandbox Code Playgroud)
我可以想到各种解决方法,但我想知道是否可以case
在 bash 中使用变量作为条件。是否可能,如果可能,如何?
小智 25
bash 手册指出:
[[(] 模式 [ | 模式 ] ... ) 列表中的 case 词;; ] ... esac
检查的每个模式都使用波浪号扩展、参数和变量扩展、算术替换、命令替换和进程替换进行扩展。
因此:模式不使用«路径名扩展»扩展。
因此:模式不能包含“|” 里面。仅:两个模式可以用“|”连接。
这有效:
s1="foo"; s2="bar" # or even s1="*foo*"; s2="*bar*"
read choice
case $choice in
$s1|$s2 ) echo "Two val choice $choice"; ;; # not "$s1"|"$s2"
* ) echo "A Bad choice! $choice"; ;;
esac
Run Code Online (Sandbox Code Playgroud)
但是,word
匹配pattern
使用« Pathname Expansion » 规则。
和 « Extended Globbing » here , here and, here允许使用交替 ("|") 模式。
这也有效:
shopt -s extglob
string='@(foo|bar)'
read choice
case $choice in
$string ) printf 'String choice %-20s' "$choice"; ;;&
$s1|$s2 ) printf 'Two val choice %-20s' "$choice"; ;;
*) printf 'A Bad choice! %-20s' "$choice"; ;;
esac
echo
Run Code Online (Sandbox Code Playgroud)
下一个测试脚本显示匹配所有包含任一foo
或bar
任何位置的行的模式是'*$(foo|bar)*'
或 两个变量$s1=*foo*
和$s2=*bar*
测试脚本:
shopt -s extglob # comment out this line to test unset extglob.
shopt -p extglob
s1="*foo*"; s2="*bar*"
string="*foo*"
string="*foo*|*bar*"
string='@(*foo*|*bar)'
string='*@(foo|bar)*'
printf "%s\n" "$string"
while IFS= read -r choice; do
case $choice in
"$s1"|"$s2" ) printf 'A first choice %-20s' "$choice"; ;;&
$string ) printf 'String choice %-20s' "$choice"; ;;&
$s1|$s2 ) printf 'Two val choice %-20s' "$choice"; ;;
*) printf 'A Bad choice! %-20s' "$choice"; ;;
esac
echo
done <<-\_several_strings_
f
b
foo
bar
*foo*
*foo*|*bar*
\"foo\"
"foo"
afooline
onebarvalue
now foo with spaces
_several_strings_
Run Code Online (Sandbox Code Playgroud)
cho*_*oba 10
您可以使用以下extglob
选项:
shopt -s extglob
string='@(foo|bar)'
Run Code Online (Sandbox Code Playgroud)
您需要两个变量,case
因为 or管道在模式扩展之前|
被解析。
v1=foo v2=bar
case foo in ("$v1"|"$v2") echo foo; esac
Run Code Online (Sandbox Code Playgroud)
foo
Run Code Online (Sandbox Code Playgroud)
变量中的 Shell 模式在带引号或不带引号时的处理方式也不同:
foo
Run Code Online (Sandbox Code Playgroud)
not a question mark
Run Code Online (Sandbox Code Playgroud)