测试glob在bash中是否有任何匹配项

测试glob在bash中是否有任何匹配项,bash,glob,Bash,Glob,如果要检查单个文件是否存在,可以使用test-e filename或[-e filename]对其进行测试 假设我有一个glob,我想知道是否存在名称与glob匹配的文件。glob可以匹配0个文件(在这种情况下,我不需要做任何事情),也可以匹配1个或多个文件(在这种情况下,我需要做一些事情)。如何测试glob是否有匹配项?(我不在乎有多少个匹配项,最好使用一个if语句,不使用循环(因为我发现它最可读) (test-e glob*如果glob与多个文件匹配,则失败。) 请注意,如果存在大量匹配项或

如果要检查单个文件是否存在,可以使用
test-e filename
[-e filename]
对其进行测试

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

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


请注意,如果存在大量匹配项或文件访问速度慢,则这可能会非常耗时。

根据MYYN的想法,稍微简化MYYN的回答:

M=(*py)
if [ -e ${M[0]} ]; then
  echo Found
else
  echo Not Found
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匹配了某些内容。

nullglob shell选项确实是一个bashism

为了避免繁琐地保存和恢复nullglob状态,我只在扩展glob的子shell中设置它:

if test -n "$(shopt -s nullglob; echo glob*)"
then
    echo found
else
    echo not found
fi
要获得更好的可移植性和更灵活的全球定位,请使用find:

if test -n "$(find . -maxdepth 1 -name 'glob*' -print -quit)"
then
    echo found
else
    echo not found
fi
显式-print-quit操作用于查找而不是默认的隐式-print操作,这样查找将在找到与搜索条件匹配的第一个文件后立即退出。如果有大量文件匹配,则该操作的运行速度应远快于
echo glob*
lsglob*
并且它还避免了过度填充扩展命令行的可能性(某些shell的长度限制为4K)

如果find感觉过度,并且可能匹配的文件数量很小,请使用stat:

if stat -t glob* >/dev/null 2>&1
then
    echo found
else
    echo not found
fi
基于此,对我来说,最简单(不一定最快)的方法就是使用查找本身,同时将glob扩展保留在shell上,如:

find /some/{p,long-p}ath/with/*globs* -quit &> /dev/null && echo "MATCH"
或者在
中,如果类似:

if find $yourGlob -quit &> /dev/null; then
    echo "MATCH"
else
    echo "NOT-FOUND"
fi
我喜欢

这既可读又高效(除非有大量文件)。
主要缺点是它比看起来要微妙得多,有时我觉得不得不添加一个长评论。
如果存在匹配项,
“glob*”
由shell展开,所有匹配项都传递给
exists()
,后者将检查第一个匹配项并忽略其余的。
如果没有匹配项,
“glob*”
将被传递到
exists()
并发现在那里也不存在


编辑:可能存在误报,请参阅测试-e有一个不幸的警告,它认为断开的符号链接不存在。因此,您可能也需要检查这些链接

function globexists {
  test -e "$1" -o -L "$1"
}

if globexists glob*; then
    echo found
else
    echo not found
fi

如果你有globfail设置,你可以使用这个疯狂的(你真的不应该)


我还有另一个解决办法:

if [ "$(echo glob*)" != 'glob*' ]
这对我来说很好。我错过了一些角落的案子吗

Bash特定解决方案:

if [ "$(echo glob*)" != 'glob*' ]
ls | grep-q“glob.*”


这不是最有效的解决方案(如果目录中有大量文件,可能会很慢),但它简单、易于阅读,而且还有一个优点,即正则表达式比普通的bash glob模式更强大。

我没有看到这个答案,所以我想把它放在那里:

[ `ls glob* 2>/dev/null | head -n 1` ] && echo true
set -- glob*
[ -f "$1" ] && echo "found $@"

在Bash中,您可以全局定位到一个数组;如果全局定位不匹配,您的数组将包含一个与现有文件不对应的条目:

#!/bin/bash

shellglob='*.sh'

scripts=($shellglob)

if [ -e "${scripts[0]}" ]
then stat "${scripts[@]}"
fi
注意:如果设置了
nullglob
scripts
将是一个空数组,您应该使用
[“${scripts[*]}]
[“${scripts[*]}”!=0]
进行测试。如果您正在编写的库必须使用或不使用
nullglob
,则需要

if [ "${scripts[*]}" ] && [ -e "${scripts[0]}" ]
这种方法的一个优点是,您可以获得要处理的文件列表,而不必重复glob操作

set -- glob*
if [ -f "$1" ]; then
  echo "It matched"
fi
解释 当与
glob*
不匹配时,
$1
将包含
'glob*'
。测试
-f“$1”
将不为真,因为
glob*
文件不存在

为什么这比其他选择更好 这适用于sh和派生类:ksh和bash。它不创建任何子shell。
$(..)
```
命令创建子shell;它们派生一个进程,因此比此解决方案慢。

类似于(包含
模式的测试文件)

shopt-s nullglob
compgen-W*模式*&>/dev/null
每箱$?英寸
0)回显“仅一个文件匹配”;;
1) 回显“多个文件匹配”;;
2) 回显“无文件匹配”;;
以撒
它比compgen-G
好得多:因为我们可以更准确地鉴别更多的情况

只能使用一个通配符
*

在bash中使用扩展全局(
extglob
)的解决方案:
bash-c$'shopt-s extglob\n/bin/ls-1U'
如果至少有一个匹配项,则退出状态为0,如果没有匹配项,则退出状态为非零(2)
stdout
包含以换行符分隔的匹配文件列表(以及包含引用空格的文件名)

或者,稍有不同:

bash -c $'shopt -s extglob \n compgen -G <ext-glob-pattern>'
至少一个匹配项:

$ 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
if compgen -G "/tmp/someFiles*" > /dev/null; then
    echo "Some files exist."
fi
[ `ls glob* 2>/dev/null | head -n 1` ] && echo true
set -- glob*
[ -f "$1" ] && echo "found $@"
#!/bin/bash

shellglob='*.sh'

scripts=($shellglob)

if [ -e "${scripts[0]}" ]
then stat "${scripts[@]}"
fi
if [ "${scripts[*]}" ] && [ -e "${scripts[0]}" ]
set -- glob*
if [ -f "$1" ]; then
  echo "It matched"
fi
bash -c $'shopt -s extglob \n compgen -G <ext-glob-pattern>'
$ 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