문 테스트 |
로 a로 구분된 다양한 문자열로 구성된 변수를 사용하려고 합니다 . case
예를 들어:
string="\"foo\"|\"bar\""
read choice
case $choice in
$string)
echo "You chose $choice";;
*)
echo "Bad choice!";;
esac
foo
or 을 입력 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에서 변수를 조건부로 사용할 수 있는지 궁금합니다. 가능합니까? 가능하다면 어떻게 달성할 수 있나요?
답변1
Bash 매뉴얼에는 다음과 같이 명시되어 있습니다.
[ [(] 패턴 [ | 패턴] ... ) 목록의 대문자 및 소문자 단어 ] ... 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
"확장된 와일드카드"를 사용하세요
그러나 "경로 이름 확장" 규칙을 사용하여 일치하는 항목이 있습니다 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_
답변2
다음 extglob
옵션을 사용할 수 있습니다.
shopt -s extglob
string='@(foo|bar)'
답변3
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
답변4
AWK의 구문을 사용할 수 있습니다
if($field ~ /regex/)
또한
if($i ~ var)
변수를 입력과 비교합니다(var 및 star 매개변수 목록 $*
).
parse_arg_exists() {
[ $# -eq 1 ] && return
[ $# -lt 2 ] && printf "%s\n" "Usage: ${FUNCNAME[*]} <match_case> list-or-\$*" \
"Prints the argument index that's matched in the regex-case (~ patn|patn2)" && exit 1
export arg_case=$1
shift
echo "$@" | awk 'BEGIN{FS=" "; ORS=" "; split(ENVIRON["arg_case"], a, "|")} {
n=-1
for(i in a) {
for(f=1; f<=NF; f++) {
if($f ~ a[i]) n=f
}
}
}
END {
if(n >= 0) print "arg index " n "\n"
}'
unset arg_case
}
string="--dot|-d"
printf "testing %s\n" "$string"
args="--dot -b -c"; printf "%s\n" "$args"
parse_arg_exists "$string" "$args"
args="-b -o"; printf "%s\n" "$args"
parse_arg_exists "$string" "$args"
args="-b -d -a"; printf "%s\n" "$args"
parse_arg_exists "$string" "$args"
인쇄하다:
testing --dot|-d
--dot -b -c
arg index 1
-b -o
-b -d -a
arg index 2