Shell中通配符的具体使用

寻技术 Linux / 其他编程 2023年07月11日 156

1. 通配符(Wildcard)

在 Shell 中命令中,通常会使用通配符表达式来匹配一些文件,如以下命令可以查找当前目录下所有后缀为 .xml 的文件

find . -name "*.xml" 

Shell 中可以使用的通配符如下:

通配符 含义 实例
* 匹配 0 或多个字符 a*b,a与b之间可以有任意长度的任意字符, 也可以一个也没有, 如 aabcb, axyzb, a012b, ab
? 匹配任意单个字符 a?b,a与b之间有且只有一个字符, 可以是任意字符, 如 aab, abb, acb, a0b
[list] 匹配 list 中的任意单个字符 a[xyz]b,a与b之间必须也只能有一个字符, 但只能是 x 或 y 或 z, 如 axb, ayb, azb。
[!list] 匹配除 list 中的任意单一字符 a[!0-9]b,a与b之间必须也只能有一个字符, 但不能是阿拉伯数字, 如 axb, aab, a-b。
[c1-c2] 匹配 c1-c2 中的任意单一字符 a[0-9]b,匹配0与9之间其中一个字符,如 a0b, a1b... a9b
{s1,s2,...} 匹配 s1 或 s2 (或更多)中的一个字符串 a{abc,xyz,123}b,a与b之间只能是abc或xyz或123这三个字符串之一

2. 转义字符

有的时候,我们匹配的内容里面会存在 *?[等通配符中的符号。为了表示他们原来的意思,我们需要使用转义字符 \,如 a\[ac\]c 表示匹配 a[a]ca[c]c\ 本身用 \\ 表示。

3. 例子

有时,我们需要对当前目录中的所有文件进行操作,比如用 tar 命令将当前目录下的所有文件打包,又如用 scp 命令将当前目录下的所有文件传输到另一台主机上。以 scp 的使用为例,我们可能会这么写这个命令:

scp -r * username@hostname:path

但是,有的时候会发现一些奇怪的问题。比如说,我在本机开着 vim 编辑着一个文件,编辑完了之后 w 保存,然后用上面的命令把当前目录下的文件传到另一台主机。如果你在另一台主机上用 vim 打开这个文件,vim 会报错,

Swap file ".filename.swp" already exists!

这是因为 vim 在打开一个文件编辑时,会产生一个 Swap file,这个 file 里面存的是编辑时对文档产生的改变,当 Vim 崩溃了之类的问题发生时,可以从这个 Swap file 恢复。Swap file 会在退出该文档时被移除。如果用户试图打开一个已存在 Swap file 的文档时,vim 就会报错,防止多个用户同时编辑同个文件的情况的发生。

由于之前只保存了文档而没有退出,所以这个暂时性的 Swap file 还存在当前目录中,随着 scp 命令一起被传送到了目标主机中。

在我们的期望中,是不希望这个暂时性的文件被传输的。由于 Swap file 的格式为 .filename.swp。我们可在开头的 . 做文章,让 scp 不传输以 . 开头的文件。

 scp -r [!.]* username@hostname:path

. 开头的文件一般为配置文件,缓存之类,通常都是不希望被传输的。(有时候传输了之后,发现有问题,但是 ls 了半天也没找出问题,因为他们默认是隐藏的,用 ls -a 才能查看)。

4. 分清楚通配符表达式和正则表达式

通配符看起来和正则表达式很像,但他们并不是同一种东西。正则表达式中的那些量词的匹配规则和这里提到的几个通配符的匹配规则并不相同。如正则表达式中 * 表示重复前一个字符任意次, 而通配符表达式中 * 表示 0 或多个任意字符。在正则表达式中,ab* 表示的是那些 a 后面跟 0 个或多个 b 的字符串,而通配符表达式中 ab* 表示的是那些 ab 后面跟任意个字符的字符串。

而且正则表达式一般是部分匹配的,用来匹配内容中的一部分,如用正则表达式 a 去匹配 bac 这段字符串时,匹配是成功的,匹配到的内容是 a。但是通配符表达式的话是全部匹配的,表达式要匹配整个字符串才算匹配成功,如用通配符表达式 a 取匹配 bac 这段字符串时,匹配是失败的。

在 Shell 命令中,通常用通配符表达式来匹配文件名,而用正则表达式来匹配一段文本内容。以 grep 命令为例,grep 命令可以在指定的文件中,挑选出和表达式匹配的那些行,其中指定文件是用的通配符表达式,而文本内容的匹配用的是正则表达式。

今天使用 grep 时,就因为没分清楚他们,忙活了半天。情况是这样的,我想看一个 jar 包里是不是有 pom 相关的文件,所以就输入了下面命令

jar tf maven-model-builder-3.5.3.jar | grep 'pom*'

结果输入了一堆文件,而且很多文件都没有 pom 这串字符串的。输出内容是这样的:

...
org/apache/maven/model/composition/
org/apache/maven/model/interpolation/
org/apache/maven/model/superpom/
org/apache/maven/model/composition/DependencyManagementImporter.class
...

这就是因为我把通配符表达式和正则表达式搞混了,后来知道原因后,用下面的命令才得到想要的内容。

jar tf maven-model-builder-3.5.3.jar | grep 'pom.*'

使用 Shell 命令时,要分清楚哪里用的是通配符表达式,哪里用的是正则表达式。

关闭

用微信“扫一扫”