bash之通配符

为什么要写这篇文章

我相信很多人和我一样,天天在使用Linux的shell命令,也大概知道有通配符这么个概念,不过比较模糊。平时也会使用简单的通配符,也许还知道有正则表达式的存在,甚至不清楚两者的区别,往往搞混淆。

我也是同样的问题,从来没有好好地静下心来总结这些东西。其实学习东西还是要踏实,这样才能发挥工具最大的作用,不是吗?本篇文章就shell的通配符来做个总结,方便以后自己查找记忆。注意,这里的shell我指的是bash,因为我几乎就没用过其它的shell,哈哈。


通配符的概念

如果查阅bash的手册或者man文档,我们发现根本压根没有通配符(wildcard)这个字眼,是不是很奇怪呢?进一步查看,转而发现这个通配符概念是路径扩展(英文pathname expansion,或者是文件名扩展(filename expansion))功能中的模式匹配(pattern matching)功能。是不是有点意外呢?

哦,原来在bash中存在很多种形式的扩展(expansion),而路径扩展(或者说文件名扩展)只是其中之一而已,了解这点尤为关键。

那么bash中具体有哪些扩展呢?我们不妨列出来,如下:

  • brace expansion  (花括号扩展)
  • tilde expansion (波浪号扩展)
  • parameter and variable expansion (参数和变量扩展)
  • arithmetic expansion (算术扩展)
  • command substitution (命令置换)
  • word splitting (单词分割)
  • filename expansion (文件名扩展)
  • process substitution(进程替换)

好,本篇文章强调的通配符概念就是文件名扩展中的模式匹配知识点。OK,那么现在我们的问题就转变成了什么是bash的文件名扩展功能什么是文件名扩展功能中的模式匹配(pattern matching)bash又是如何处理这些功能的

很好理解,就是bash在扫描命令行参数(不了解命令行参数的组成部分的童鞋可以参考文章《学会使用getopt函数》)时会注意操作数(Operands)部分是否有*?,和[这些特殊模式字符(special pattern characters)。当它发现这些特殊模式字符时,会将它们视为要匹配的模式。通俗点说,就是bash发现参数部分有这些特殊字符时,会扩展这些符号,生成相应的已存在的文件名或者目录,最后经过排序后传递给命令


模式匹配

好了,到这里,我们应该了解到,平时说的所谓通配符在bash中的专业叫法是模式匹配(pattern matching)。

这里顺便提一下,这个模式匹配相比正则表达式而言,那是简单多了,有关正则表达式可以参阅这篇文章《常用正则表达式整理》。

接下来,就让我们详细地了解bash中的特殊模式字符吧。


特殊模式字符以及含义

首先把上图列出的特殊模式字符分为两类:?*[set]是最常见的特殊模式字符,在几乎所有的shell中都支持;而后5项是bash的扩展特殊字符,如果想使用,请确保extglob是设置着的,即shopt -s extglob.

好了,接下来结合实际的例子来学些这些特殊模式字符吧!首先是常见的特殊模式字符。

特殊模式字符?匹配任何的单一字符。因此如果目录下有whizprog.c、whizprog.log与whizprog.o这三个文件,那么表达式whizprog.?匹配的结果是whizprog.c和whizprog.o,但是whizprog.log不匹配。

特殊模式字符*是一个功能强大而且广为使用的通配符,它匹配于任何字符组成的字符串(包括空字符串)。表达式whiziprog.*匹配前面提到的三个文件;网页设计人员可以使用*.html表达式匹配他们的所有输入文件。

关于特殊模式字符*,bash有个选项globstar来控制连续两个星号的行为,即出现**的情况:


什么意思呢? 意思就是说选项globstar在disable(shopt -u globstar)情况下,***的行为是一样的。但是一旦enable(shopt -s globstar),那么**就会递归匹配所有的文件和目录,而**/仅会递归匹配所有的目录。通过以下实例可以看出实际区别:

  1. [10:06:14@astrol:/etc/systemd]# pwd && ls  
  2. /etc/systemd  
  3. journald.conf  logind.conf  network  resolved.conf  system  system.conf  timesyncd.conf  user  user.conf  
  4. [10:06:28@astrol:/etc/systemd]# shopt globstar  
  5. globstar        off  
  6. [10:06:36@astrol:/etc/systemd]#  
  7. [10:06:38@astrol:/etc/systemd]# echo *; echo **  
  8. journald.conf logind.conf network resolved.conf system system.conf timesyncd.conf user user.conf  
  9. journald.conf logind.conf network resolved.conf system system.conf timesyncd.conf user user.conf  
  10. [10:06:46@astrol:/etc/systemd]# echo */; echo **/  
  11. network/ system/ user/  
  12. network/ system/ user/  
  13. [10:06:53@astrol:/etc/systemd]# shopt -s globstar  
  14. [10:07:00@astrol:/etc/systemd]# echo *; echo **  
  15. journald.conf logind.conf network resolved.conf system system.conf timesyncd.conf user user.conf  
  16. journald.conf logind.conf network network/90-mac-for-usb.link network/99-default.link resolved.conf system system/basic.target.wants system/basic.target.wants/live-config.service system/clamav-daemon.service.d system/clamav-daemon.service.d/extend.conf system.conf system/dbus-org.freedesktop.ModemManager1.service system/dbus-org.freedesktop.nm-dispatcher.service system/default.target system/display-manager.service system/getty.target.wants system/getty.target.wants/getty@tty1.service system/graphical.target.wants system/graphical.target.wants/accounts-daemon.service system/hibernate.target.wants system/hibernate.target.wants/anacron-resume.service system/hybrid-sleep.target.wants system/hybrid-sleep.target.wants/anacron-resume.service system/iodined.service system/multi-user.target.wants system/multi-user.target.wants/anacron.service system/multi-user.target.wants/binfmt-support.service system/multi-user.target.wants/console-setup.service system/multi-user.target.wants/cron.service system/multi-user.target.wants/inetd.service system/multi-user.target.wants/irqbalance.service system/multi-user.target.wants/live-tools.service system/multi-user.target.wants/ModemManager.service system/multi-user.target.wants/networking.service system/multi-user.target.wants/NetworkManager.service system/multi-user.target.wants/nmbd.service system/multi-user.target.wants/openbsd-inetd.service system/multi-user.target.wants/pppd-dns.service system/multi-user.target.wants/remote-fs.target system/multi-user.target.wants/rsync.service system/multi-user.target.wants/rsyslog.service system/multi-user.target.wants/smartd.service system/multi-user.target.wants/smbd.service system/multi-user.target.wants/ssh.service system/multi-user.target.wants/vsftpd.service system/network-online.target.wants system/network-online.target.wants/networking.service system/samba-ad-dc.service system/sockets.target.wants system/sockets.target.wants/dm-event.socket system/sockets.target.wants/pcscd.socket system/sockets.target.wants/uuidd.socket system/sshd.service system/suspend.target.wants system/suspend.target.wants/anacron-resume.service system/sysinit.target.wants system/sysinit.target.wants/keyboard-setup.service system/sysinit.target.wants/lvm2-lvmetad.socket system/sysinit.target.wants/lvm2-lvmpolld.socket system/sysinit.target.wants/systemd-timesyncd.service system/syslog.service timesyncd.conf user user.conf  
  17. [10:07:05@astrol:/etc/systemd]#  
  18. [10:08:12@astrol:/etc/systemd]# echo */; echo **/  
  19. network/ system/ user/  
  20. network/ system/ system/basic.target.wants/ system/clamav-daemon.service.d/ system/getty.target.wants/ system/graphical.target.wants/ system/hibernate.target.wants/ system/hybrid-sleep.target.wants/ system/multi-user.target.wants/ system/network-online.target.wants/ system/sockets.target.wants/ system/suspend.target.wants/ system/sysinit.target.wants/ user/  
  21. [10:08:23@astrol:/etc/systemd]#  

OK,接着看特殊模式字符[set],它与特殊模式字符?很相似,但允许匹配的更确切,把所有想要匹配的字符放在[ ]内,结果匹配其中的任一字符。可以使用波折号-表示范围,也可以使用第一个字符是!或者是^来表示反向匹配。举例如下:

whiziprog.[co]whizprog.[a-z]匹配文件whizprog.c和whizprog.o,但不匹配文件whizprog.log。

[abc][a-c]匹配字符a、b或c

[!0-9]或者[^0-9]匹配任何一个非数字字符

[a-zA-Z0-9_-]匹配任何一个字母、任何一个数字、下划线或者破折号(假设ASCII环境下)。


好了,介绍完了几个常见的特殊模式字符后,我们来看看bash的几个扩展特殊模式字符。使用它们之前,请确保选项extglob是打开的(shopt -s extglob)。

怎么说呢,有了这几个扩展的特殊模式字符,就使得模式匹配有了点正则表达式的味道,自此模式匹配也有了重复、可选的功能了。


注意,这里的pattern-list可以是符号|隔开的模式,表示可选功能。好了,废话不多说,让我们看几个实际例子吧。

(1)列出当前目录下以“ab”或者“def”打头的JPEG或者GIF文件

ls +(ab|def)*.+(jpeg|gif)

(2)列出当前目录下匹配与正则表达式ab(2|3)+\.jpg的所有文件

ls ab+(2|3).jpg

匹配到的文件名诸如ab2.jpg,ab222.jpg,ab3.jpg,ab333.jpg等。

(3)删除当前目录下的jpeg文件或者gif文件,你可能会写出以下表达式:

rm -rf *!(.jpeg|.gif)

但是很遗憾,结果是不对的!这条命令会把当前目录下的所有文件删除。为什么呢?这是因为一开始的星号(*)匹配了所有的文件,当然就包括以.jpeg和.gif为后缀的文件。正确的写法如下:

rm -rf !(*.jpeg|*.gif)

(4)如何列出(1)中的方向结果呢?很简单加个括号在取反就OK!

ls !(+(ab|def)*.+(jpeg|gif))


参考链接:

bash八大扩展一网打尽

shopt nullglob, failglob, extglob, globstar用法

Bash Extended Globbing

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值