我想判断一个字符串$string是否会被一个 glob 模式匹配$pattern。 $string可能是也可能不是现有文件的名称。我怎样才能做到这一点?
假设我的输入字符串采用以下格式:
string="/foo/bar"
pattern1="/foo/*"
pattern2="/foo/{bar,baz}"
Run Code Online (Sandbox Code Playgroud)
我想找到一个bash成语,决定是否$string将被匹配$pattern1,$pattern2或任何其它任意的glob模式。这是我迄今为止尝试过的:
[[ "$string" = $pattern ]]
这几乎有效,除了$pattern被解释为字符串模式而不是全局模式。
[ "$string" = $pattern ]
这种方法的问题$pattern是 展开然后在$string和 的展开之间执行字符串比较$pattern。
[[ "$(find $pattern -print0 -maxdepth 0 2>/dev/null)" =~ "$string" ]]
这个有效,但前提是$string包含存在的文件。
[[ $string =~ $pattern ]]
这不起作用,因为=~运算符导致$pattern被解释为扩展的正则表达式,而不是 glob 或通配符模式。
jay*_*ren 10
这个问题没有通用的解决方案。原因是,在 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
Run Code Online (Sandbox Code Playgroud)
运行此脚本会生成以下输出:
/foo/* matches /foo/bar
/foo/bar* matches /foo/bar
/foo/** matches /foo/bar
Run Code Online (Sandbox Code Playgroud)
这是有效的,因为set -f禁用了路径名扩展,因此语句中只发生大括号扩展和波浪号扩展for pattern in /foo/{*,foo*,bar*,**,**/*}。然后,我们可以[[ $string == $pattern ]]在执行大括号扩展后使用测试操作 来测试路径名扩展。
我不相信这{bar,baz} 是一个 shell glob 模式(虽然肯定/foo/ba[rz]是)但是如果你想知道是否$string匹配,$pattern你可以这样做:
case "$string" in
($pattern) put your successful execution statement here;;
(*) this is where your failure case should be ;;
esac
Run Code Online (Sandbox Code Playgroud)
您可以随心所欲地进行:
case "$string" in
($pattern1) do something;;
($pattern2) do differently;;
(*) still no match;;
esac
Run Code Online (Sandbox Code Playgroud)