$string
文字列がグローバルパターンと一致するかどうかを知りたいです$pattern
。 $string
既存のファイルの名前であってもなくてもよい。どうすればいいですか?
私の入力文字列が次の形式であるとしましょう。
string="/foo/bar"
pattern1="/foo/*"
pattern2="/foo/{bar,baz}"
$string
bashイディオムが一致するか、他の任意のグローバルパターンと一致するかどうかを確認します。これまでに試したことは次のとおりです。$pattern1
$pattern2
[[ "$string" = $pattern ]]
$pattern
グローバルパターンではなく文字列パターンとして解釈されることを除いて、ほとんど機能します。[ "$string" = $pattern ]
このアプローチの問題は、文字列が拡張された後と
$pattern
拡張の間で文字列比較が実行されることです。$string
$pattern
[[ "$(find $pattern -print0 -maxdepth 0 2>/dev/null)" =~ "$string" ]]
この方法は機能しますが、
$string
ファイルが存在する場合にのみ可能です。[[ $string =~ $pattern ]]
=~
演算子は$pattern
グローバルまたはワイルドカードパターンではなく拡張正規表現として解釈されるため、これは機能しません。
答え1
この問題に対する普遍的な解決策はありません。その理由は、bashで中括弧拡張(別名{pattern1,pattern2,...}
およびファイル名拡張(別名globパターン))が別々に扱われ、異なる条件と時間に拡張されるためです。以下は、bashで実行される拡張の完全なリストです。
- 支柱の拡張
- チルダ拡張
- パラメータと変数の拡張
- コマンドの置き換え
- 算術拡張
- 噴射
- パス名拡張
これらのサブセット(おそらく中括弧、チルダ、パス名の拡張)にのみ興味があるため、特定のパターンとメカニズムを使用して制御可能な方法で拡張を制限できます。たとえば、
#!/bin/bash
set -f
string=/foo/bar
for pattern in /foo/{*,foo*,bar*,**,**/*}; do
[[ $string == $pattern ]] && echo "$pattern matches $string"
done
このスクリプトを実行すると、次の出力が生成されます。
/foo/* matches /foo/bar
/foo/bar* matches /foo/bar
/foo/** matches /foo/bar
これはset -f
、パス名拡張が無効になっているため、ステートメントで中括弧拡張とチルダ拡張のみが発生するために機能しますfor pattern in /foo/{*,foo*,bar*,**,**/*}
。その後、中[[ $string == $pattern ]]
かっこ拡張を実行した後、テスト操作を使用してパス名拡張をテストできます。
答え2
私は信じていません{bar,baz}
はいシェルグローバルモード(もちろんそうですが/foo/ba[rz]
)$string
しかし、一致するものがあるかどうかを知りたい場合は、$pattern
次のようにします。
case "$string" in
($pattern) put your successful execution statement here;;
(*) this is where your failure case should be ;;
esac
好きなだけ多くのことができます。
case "$string" in
($pattern1) do something;;
($pattern2) do differently;;
(*) still no match;;
esac
答え3
Patrickが指摘したように、「異なる種類」のスキーマが必要です。
[[ /foo/bar == /foo/@(bar|baz) ]]
string="/foo/bar"
pattern="/foo/@(bar|baz)"
[[ $string == $pattern ]]
そこには引用符は必要ありません。
答え4
$string
保存されたglob拡張によるファイルパスにあることを確認する場合$pattern
(他の人が言ったように、{foo,bar}
これはglob演算子ではないことを覚えておいてください)zsh
。
if ()(($#)) $~pattern(NY1e['[[ $REPLY = $string ]]']); then
print -r -- "$string is among the result of the $pattern glob expansion"
fi
を使用すると、bash
いつでもループを使用できます。
among() (
string=$1 pattern=$2 IFS=
shopt -s nullglob extglob
for file in $pattern@(); do
[[ "$string" = "$file" ]] && return
done
false
)
if among "$string" "$pattern"; then
printf '%s\n' "$string is among the result of the $pattern glob expansion"
fi
(extglob
有効にすると、次のようなものを使用できるksh拡散演算子のサブセットを有効にできます。foo/@(foo|bar)
上記@()
のパターンに加えてグローバル拡散を強制します。これがなければ、存在しなくてもamong foo foo
trueが返されますfoo
。 donを使用すると、/
最後にパターンが適用されません(例among /bin/ '/*/'
:)。
スプリット+グロブに加えて、中かっこの拡張は、有効でなく無効になっていない限り、引数のksh
拡張中に行われます。 / に対応するglob演算子もあるので、次のようにできます。noglob
braceexpand
ksh93
~(N)
zsh
bash
nullglob
function among {
typeset string="$1" pattern="$2" IFS= file
set -o braceexpand +o noglob
for file in ~(N)$pattern; do
[[ "$string" = "$file" ]] && return
done
false
}
among foo/bar 'foo/{bar,baz}'
ファイルが存在する限りtrueを返しますfoo/bar
。
kshの拡張glob演算子は、他の拡張の結果では認識されません(a='@(x)'; echo $a
出力のPOSIX要件に準拠するため)。@(x)
これらすべてまたは文字列がパターンと一致していてもfalseを返しamong .foo '*'
ますamong /etc/issue '*'
。among /usr/local/bin '/*/bin'