测试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
- 使用
前缀,以便解释$
,从而使扩展glob模式位于与\n
不同的行上,否则扩展glob模式将是语法错误李>shopt-s extglob
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