详解shell命令行glob规则

Last Updated: 2023-07-10 06:49:19 Monday

-- TOC --

glob的由来:很久很久以前,在UNIX v6中,有一个程序名叫/etc/glob,它能够用来扩展wildcard pattern,不久后,这个功能内置进了shell。

glob [ɡlɔb] n. a compact mass

glob也被称为模式扩展,与正则表达式的关系是,模式扩展早于正则表达式出现,可以看作是原始的正则表达式。它的功能没有正则那么强大和灵活,但是优点是简单和方便。

当Bash命令行使用glob时,先扩展,再执行命令。因此,扩展的结果是由Bash负责,与所要执行的命令无关。命令本身收到什么参数就原样执行。这一点务必需要搞清楚!(因为这个原因,很多命令都支持多参数,即globbing后的pathname list)

Bash的glob规则,同样适用于各种parameter expansion!在官方文档中,glob被称为Pattern Match!

Wildcard匹配规则

一个字符串属于wildcard pattern,它需要包含?*[3个符号中的任意一个。Globbing这个动作的操作,就是将wildcard pattern扩展成一个符合此pattern的pathname list,可能是list哦!

?:当不在[]内时,匹配任意单个字符。

*:当不在[]内时,匹配任意字符串,包括空串,但不含.

显示隐藏文件,要使用ls .*

[...]:表示字符集合,匹配任意一个此集合内的字符,[][!]匹配][!这3个字符。[[?*\]匹配[?*\这4个字符。

[a-z]:表示一个范围(ASCII range),它是集合的简化表达方式,例如[0-9]表示所有数字符号,[A-F]表示A到F这个字母范围。[--0]匹配-.0/是不能被匹配的

[!...]:匹配任意一个不在此集合范围内的字符,也是集合,表达方式不同,反过来表达。同正则表达式中的[^...]

要表示*?[本身的含义,除了将他们放入一个字符集合内之外,还可以在命令行使用\和引号来表示这些特殊符号:

$ ls b*
bootchartd.c  bootchartd.o  built-in.o
$ ls b\*
ls: cannot access 'b*': No such file or directory
$ ls b[*]
ls: cannot access 'b[*]': No such file or directory
$ ls 'b*'  # or "b*"
ls: cannot access 'b*': No such file or directory

用引号,实际上抑制了shell的globbing这个动作。

pathnames

Globbing操作分别应用在pathname的每一个由/分开的部分,这就是为什么/不能够被匹配的原因,也因此,wildcard pattern可以分段写。

$ ls in*/in*
include/inet_common.h  init/init.c  init/init.o

如果文件名由.开始,这个符号必须显式的匹配,即用一个.去匹配。因此rm *不会删除由点开始的隐藏文件,tar c *不会将所有文件打包,用tar c .更好。

glob规则产生的都是pathname,是一个list!

empty lists

Globbing后得到一个empty list是可能的,POSIX规定:POSIX requires that a wildcard pattern is left unchanged when it is syntactically incorrect(包含/), or the list of matching pathnames is empty. 就是当globbing有错或为空时,wildcard pattern保持不变,命令使用这个pattern字符串本身。

$ ls k*
ls: cannot access 'k*': No such file or directory
$ shopt -s nullglob
$ ls k*
bootchartd.c  built-in.o  Config.src  halt.o  init.o  Kbuild.src  reboot.h
bootchartd.o  Config.in   halt.c      init.c  Kbuild  lib.a

当使用shopt设置nullglob开关后,k*为空,命令行就只剩下ls自己了!因此,默认情况下,glob出现空list的时候,可能会导致命令行执行错误。bash的shopt提供了一个开关来关闭这个默认的行为模式。

查找所有子目录

$ echo */
cmake_test/ cs231n_assignment/ opencv/ pyvirtualcam/
$ echo **/
cmake_test/ cs231n_assignment/ opencv/ pyvirtualcam/

与正则表达式比较

re和glob不一样,只是有相似的地方。

re中的*?+表示对前面部分的0或多次的重复,而glob中没有重复这个概念。glob中的*表示0或任意长的字符串。

re中集合补充使用[^...],glob还能使用[!...]。当然,还有很多其他不一样的地方。glob用来产生pathname list,re用来匹配字符串!

更多关于集合

前文描述了3中表达集合的方式:集合[...],补充[!...],范围[0-9]。POSIX给glob和re都补充了另外几种表达方式:

命令字符集

[:alnum:]  [:alpha:]  [:blank:]  [:cntrl:]
[:digit:]  [:graph:]  [:lower:]  [:print:]
[:punct:]  [:space:]  [:upper:]  [:xdigit:]

so that one can say [[:lower:]] instead of [a-z], and have things work in Denmark, too, where there are three letters past 'z' in the alphabet. These character classes are defined by the LC_CTYPE category in the current locale.

(v) Collating symbols, like "[.ch.]" or "[.a-acute.]", where the string between "[." and ".]" is a collating element defined for the current locale. Note that this may be a multicharacter element.

(vi) Equivalence class expressions, like "[=a=]", where the string between "[=" and "=]" is any collating element from its equivalence class, as defined for the current locale. For example, "[[=a=]]" might be equivalent to "[aáaäâ]", that is, to "[a[.a-acute.][.a-grave.][.a-umlaut.][.a-circumflex.]]".

extglob

看了下bash的extglob选项默认居然是打开的,那就更必须要学习了。

$ shopt | grep glob
dotglob         off
extglob         on
failglob        off
globasciiranges off
globstar        off
nocaseglob      off
nullglob        off

If the extglob shell option is enabled using the shopt builtin, several extended pattern matching operators are recognized. In the following description, a pattern-list is a list of one or more patterns separated by a |. Composite patterns may be formed using one or more of the following sub-patterns:

pattern-list由|符号分割。

?(pattern-list)

Matches zero or one occurrence of the given patterns.

*(pattern-list)

Matches zero or more occurrences of the given patterns.

+(pattern-list)

Matches one or more occurrences of the given patterns.

@(pattern-list)

Matches one of the given patterns.

!(pattern-list)

Matches anything except one of the given patterns.

Complicated extended pattern matching against long strings is slow, especially when the patterns contain alternations and the strings contain multiple matches. Using separate matches against shorter strings, or using arrays of strings instead of a single long string, may be faster.

例如,显示所有v和t开头的文件或目录:

$ echo *(v*|t*)

本文链接:https://cs.pynote.net/sf/linux/shell/202111161/

-- EOF --

-- MORE --