ステートメントテスト|
で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;;
調査された各パターンは、チルダ拡張、パラメータおよび変数拡張、算術置換、コマンド置換、およびプロセス置換を使用して拡張されます。
「パス名拡張」なし
したがって、スキーマは「パス名の拡張」では拡張されません。
したがって、パターン内に「|」を含めることはできません。固有:「|」を使用して2つのパターンをリンクできます。
これは働きます:
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
次のテストスクリプトは、2つのうちの1つまたは任意の場所を含むすべての行に一致するパターンが変数とその両方の1つまたは両方であることを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