加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 综合聚焦 > 服务器 > 安全 > 正文

Bash检查文件是否存在双括号测试和通配符

发布时间:2020-12-15 22:48:01 所属栏目:安全 来源:网络整理
导读:我正在写一个 Bash脚本,需要检查一个文件是否存在,看起来像*.$1.*.ext我可以很容易地用POSIX测试做到这一点,因为[-f *.$1.*.ext]返回true,但使用双括号[[-f *.$1.*.ext]]失败. 这只是为了满足好奇心,因为我无法相信扩展测试无法判断文件是否存在.我知道我可
我正在写一个 Bash脚本,需要检查一个文件是否存在,看起来像*.$1.*.ext我可以很容易地用POSIX测试做到这一点,因为[-f *.$1.*.ext]返回true,但使用双括号[[-f *.$1.*.ext]]失败.

这只是为了满足好奇心,因为我无法相信扩展测试无法判断文件是否存在.我知道我可以使用[[`ls *.$1.*.ext`]]但如果有多个匹配则匹配.我可能会把它管到wc或其他东西,但这看起来很笨重.

是否有一种简单的方法可以使用双括号来检查是否存在使用通配符的文件?

编辑:我看到[[-f`ls -U *.$1.*.ext`]]有效,但我仍然不想打电话给ls.

解决方法

[-f …]和[[-f …]](以及其他文件测试运算符)都不能用于处理模式(aka globs,通配符表达式) – 它们总是将其操作数解释为文字文件名. [1]

测试模式(glob)是否与一个文件完全匹配的一个简单技巧是使用辅助函数:

existsExactlyOne() { [[ $# -eq 1 && -f $1 ]]; }

if existsExactlyOne *."$1".*.ext; then # ....

如果您只是对是否有任何匹配感兴趣 – 即一个或多个 – 该功能甚至更简单:

exists() { [[ -f $1 ]]; }

如果你想避免一个函数,它会变得更棘手:

警告:例如,此解决方案不区分常规文件目录(尽管可以修复).

if [[ $(shopt -s nullglob; set -- *."$1".*.ext; echo $#) -eq 1 ]]; then # ...

>命令替换中的代码($(…))执行以下操作:

> shopt -s nullglob指示bash将模式扩展为空字符串(如果没有匹配项)
> set – …将模式扩展的结果分配给运行命令替换的子shell的位置参数($1,$2,…).
> echo $#简单地回应位置参数的数量,然后对应于匹配文件的数量;

>回显的数字(命令替换的标准输出)成为-eq运算符的左侧,它(数字地)将它与1进行比较.

同样,如果您只是对是否存在任何匹配感兴趣 – 即一个或多个 – 只需将-eq替换为-ge.

[1]
正如@Etan Reisinger在评论中指出的那样,在[…](单括号语法)的情况下,shell在-f运算符甚至看到之前扩展模式(正常的命令行解析规则适用).

相比之下,不同的规则适用于bash的[[…]],它被解析得不同,在这种情况下,简单地将模式视为文字(即,不扩展它).

无论哪种方式,它都不会(强大且可预测)与模式一起工作:

> [[…]]它永远不会起作用:文件测试操作符始终将模式视为文字.
> […]只有恰好有一个匹配才能正常工作.

>如果没有匹配:

>文件测试操作符将模式视为文字,如果nullglob为OFF(默认值),或者,如果nullglob为ON,则条件总是返回true,因为它被减少为-f,由于缺少操作数,不再被解释为文件测试,而是作为非空字符串(非空字符串求值为true)).

>如果存在MULTIPLE匹配:[…]命令作为一个整体中断,因为模式然后扩展为多个单词,而文件测试运算符只接受一个参数.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读