명령문 테스트 |
로 분리 된 다른 문자열로 구성된 변수를 사용하려고합니다 case
. 예를 들면 다음과 같습니다.
string="\"foo\"|\"bar\""
read choice
case $choice in
$string)
echo "You chose $choice";;
*)
echo "Bad choice!";;
esac
문의 첫 부분 을 입력 foo
하거나 bar
실행할 수 있기를 원합니다 case
. 그러나 두 foo
와 bar
두 번째에 데려다 :
$ foo.sh
foo
Bad choice!
$ foo.sh
bar
Bad choice!
사용은 "$string"
대신에 $string
차이가 없습니다. 둘 다 사용하지 않습니다 string="foo|bar"
.
나는 이런 식으로 할 수 있다는 것을 안다.
case $choice in
"foo"|"bar")
echo "You chose $choice";;
*)
echo "Bad choice!";;
esac
다양한 해결 방법을 생각할 수 있지만 case
bash에서 변수를 조건 으로 사용할 수 있는지 알고 싶습니다 . 가능하다면 어떻게합니까?
답변
bash 매뉴얼은 다음과 같이 말합니다.
[[(] pattern [| pattern] …) 목록의 대소 문자 구분; ] … 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
«확장 글 로빙»사용
그러나 «Pathname Expansion»규칙 word
을 pattern
사용 하는 것과 일치 합니다.
그리고«확장 글 로빙» 여기 , 여기 , 그리고 여기 에서 교차 ( “|”) 패턴을 사용할 수 있습니다.
이것은 또한 작동합니다 :
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
문자열 내용
다음 테스트 스크립트는 어느 곳에 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_
답변
extglob
옵션을 사용할 수 있습니다 :
shopt -s extglob
string='@(foo|bar)'
답변
패턴이 확장 되기 전에case
또는 |
파이프가 구문 분석 되므로 두 개의 변수가 필요합니다 .
v1=foo v2=bar
case foo in ("$v1"|"$v2") echo foo; esac
foo
변수의 쉘 패턴은 인용되거나 인용되지 않을 때 다르게 처리됩니다.
q=?
case a in
("$q") echo question mark;;
($q) echo not a question mark
esac
not a question mark
답변
대시 호환 해결 방법을 원하면 다음과 같이 작성할 수 있습니다.
string="foo|bar"
read choice
awk 'BEGIN{
n=split("'$string'",p,"|");
for(i=1;i<=n;i++)
if(system("\
case \"'$choice'\" in "p[i]")\
echo \"You chose '$choice'\";\
exit 1;;\
esac"))
exit;
print "Bad choice"
}'
설명 : awk는 “문자열”을 분할하고 각 부분을 개별적으로 테스트하는 데 사용됩니다. “choice”가 현재 테스트 된 부품 p [i]와 일치하면 awk- 명령은 11 행에서 “exit”로 종료됩니다. 매우 테스트를 위해 쉘의 “case”가 사용됩니다 ( ‘시스템’호출 내). terdon의 요청에 따라 이것은 쉘의 “case”가 허용하는 것처럼 “foooo”( “search pattern”)에 대해서도 일치하도록 의도 된 test- “string”을 “foo * | bar”로 수정하는 가능성을 유지합니다. 대신 정규 표현식을 선호하는 경우 “시스템”호출을 생략하고 awk의 “~”또는 “match”를 대신 사용할 수 있습니다.