如果我想检查单个文件是否存在,我可以使用test -e filename或[-e filename]进行测试。

假设我有一个glob,我想知道是否有文件名与glob匹配的文件存在。glob可以匹配0个文件(在这种情况下,我不需要做任何事情),也可以匹配1个或多个文件(在这种情况下,我需要做一些事情)。我如何测试一个glob是否有任何匹配?(我不在乎有多少匹配,这将是最好的,如果我能做到这一点与一个if语句和没有循环(只是因为我发现最易读)。

(如果glob匹配多个文件,则test -e glob*失败。)


当前回答

在Bash中扩展glob (extglob)的解决方案:

bash -c $'shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

如果至少有一个匹配,则退出状态为0,如果没有匹配,则退出状态为非0(2)。标准输出包含一个换行分隔的匹配文件列表(以及文件名中包含引号中的空格)。

或者,稍微不同:

bash -c $'shopt -s extglob \n compgen -G <ext-glob-pattern>'

与基于ls的解决方案的区别:可能更快(未测量),输出中未引用空格的文件名,不匹配时退出代码1(而不是2:shrug:)。

使用示例:

不匹配:

$ bash -c $'shopt -s extglob \n /bin/ls -1U @(*.foo|*.bar)'; echo "exit status: $?"
/bin/ls: cannot access '@(*.foo|*.bar)': No such file or directory
exit status: 2

至少一种匹配:

$ bash -c $'shopt -s extglob \n /bin/ls -1U @(*.ts|*.mp4)'; echo "exit status: $?"
'video1 with spaces.mp4'
video2.mp4
video3.mp4
exit status: 0

概念:

ls的退出代码行为(添加-U表示效率,-1表示输出控制)。 在当前shell中不启用extglob(通常不需要)。 使用$前缀使\n被解释,因此扩展的glob模式与shopt -s extglob在不同的行上——否则扩展的glob模式将是一个语法错误!

注1:我致力于这个解决方案,因为在其他答案中建议的compgen -G“<glob-pattern>”方法似乎不能顺利地与大括号展开一起工作;但我需要一些更高级的globing功能。

注2:扩展的glob语法的可爱资源:extglob

其他回答

我还有另一个解决方案:

if [ "$(echo glob*)" != 'glob*' ]

这对我来说很有用。我可能漏掉了一些极端情况。

Bash-specific解决方案:

compgen -G "<glob-pattern>"

转义模式,否则它将被预先展开为匹配。

退出状态为:

1表示不匹配, 0表示“一个或多个匹配”

Stdout是匹配glob的文件列表。 我认为这是最好的选择,就简洁和最小化潜在的副作用而言。

例子:

if compgen -G "/tmp/someFiles*" > /dev/null; then
    echo "Some files exist."
fi

在Bash中扩展glob (extglob)的解决方案:

bash -c $'shopt -s extglob \n /bin/ls -1U <ext-glob-pattern>'

如果至少有一个匹配,则退出状态为0,如果没有匹配,则退出状态为非0(2)。标准输出包含一个换行分隔的匹配文件列表(以及文件名中包含引号中的空格)。

或者,稍微不同:

bash -c $'shopt -s extglob \n compgen -G <ext-glob-pattern>'

与基于ls的解决方案的区别:可能更快(未测量),输出中未引用空格的文件名,不匹配时退出代码1(而不是2:shrug:)。

使用示例:

不匹配:

$ bash -c $'shopt -s extglob \n /bin/ls -1U @(*.foo|*.bar)'; echo "exit status: $?"
/bin/ls: cannot access '@(*.foo|*.bar)': No such file or directory
exit status: 2

至少一种匹配:

$ bash -c $'shopt -s extglob \n /bin/ls -1U @(*.ts|*.mp4)'; echo "exit status: $?"
'video1 with spaces.mp4'
video2.mp4
video3.mp4
exit status: 0

概念:

ls的退出代码行为(添加-U表示效率,-1表示输出控制)。 在当前shell中不启用extglob(通常不需要)。 使用$前缀使\n被解释,因此扩展的glob模式与shopt -s extglob在不同的行上——否则扩展的glob模式将是一个语法错误!

注1:我致力于这个解决方案,因为在其他答案中建议的compgen -G“<glob-pattern>”方法似乎不能顺利地与大括号展开一起工作;但我需要一些更高级的globing功能。

注2:扩展的glob语法的可爱资源:extglob

#!/usr/bin/env bash

# If it is set, then an unmatched glob is swept away entirely -- 
# replaced with a set of zero words -- 
# instead of remaining in place as a single word.
shopt -s nullglob

M=(*px)

if [ "${#M[*]}" -ge 1 ]; then
    echo "${#M[*]} matches."
else
    echo "No such files."
fi

这招似乎很管用:

#!/usr/bin/env bash
shopt -s nullglob
if [ "`echo *py`" != "" ]; then
    echo "Glob matched"
else
    echo "Glob did not match"
fi

它可能需要bash,而不是sh。

这是因为如果没有匹配项,nullglob选项会导致glob计算为空字符串。因此,echo命令的任何非空输出都表明glob匹配了某些内容。