元字符(通配符)
元字符是用于表示某些特定而非其自身含义的特殊字符,shell元字符称为通配符(wildcard)。见下表
元字符 | 含义 |
---|---|
\ | 按文本含义解释后面接着的字符 |
& | 在后台运行进程 |
; | 命令分隔符 |
$ | 变量替换 |
? | 匹配一个字符 |
[abc] | 匹配一个字符集中的一个字符,如a,b,c |
[!abc] | 匹配一个字符集外的一个字符,如a,b,c |
* | 匹配零或多个字符 |
(cmds) | 在子shell中执行命令 |
{cmds} | 在当前shell中执行命令 |
文本名替换
当对命令行求值时,shell用元字符来缩写与某些字符集匹配的文件名或路径名。将元字符扩展为文件名的过程也称为文件名替换或globbing。如果使用了元字符而又没有任何文件名可匹配,shell将把该元字符视为文本字符。
元字符 | 含义 |
---|---|
* | 匹配零或多个字符 |
? | 匹配一个字符 |
[abc] | 匹配一个字符集内的一个字符,如a,b,c |
[!abc] | 匹配一个字符集外的一个字符,如非a,b,c |
{a,ile,ax} | 匹配一个字符或字符集 |
[!a-z] | 匹配从a~z范围以外的一个字符 |
\ | 转义或禁止元字符 |
{1…10} | 可以通过范围操作符来进行批量匹配 |
Note: *是匹配文件名中零个或任意个字符的通配符
$ ls *
# file.bak abc adg f.bak
$ ls *.bak
# file.bak f.bak
$ echo a*
# abc adg
$ echo c*
# c* 因为目录下不存在c开头的文件,因此会把通配符视为文本字符打印出来
$ ls
# abc abc1 abc123 abc2
$ ls a?c?
# abc1 abc2
$ echo abc???
# abc123
$ echo ??
# ?? 不存在两个字符的文件名,因此视为文本字符打印出来
方括号 这种括号用于匹配包含某个字符集或某个字符范围内的一个字符的文件名
$ ls
# abc abc1 abc123 abc122 abc2 file.bak
$ ls abc[123]
# abc1 abc2
$ ls abc[1-3]
# abc1 abc2
$ ls [a-z][a-z][a-z]
# abc
$ ls [!f-z]???
# abc1 abc2
$ ls abc12[23]
# abc122 abc123
$ ls
# a.c b.c ac ab3 ab4 fumble faa
$ ls f{oo,aa,umble} # 花括号中若有空格则会导致出错信息
# faa fumble
$ ls a{.c,c,b[3-5]}
# a.c ab3 ab4
$ mkdir /tmp/{old,new,dist,bugs}
# old new dist bugs 在/tmp目录下面创建者四个文件
$ chown root /tmp/{usr/{ex,edit},lib/{ex?.?*,how_ex}}
# 花括号也能嵌套使用,这里匹配的是/tmp/usr/ex, /tmp/usr/edit, /tmp/lib/ex1.cc, /tmp/lib/how_ex
$ echo fo{o, um}*
# fo{o,um}* 括号里面不能有空格,如果有任何一个没有用引号括起来的空格,就不会进行括号扩展
$ echo {mam,pap,ba}a
# mama papa baa
$ echo post{script,office,ure}
# postscript postoffice posture
转义字符 要将元字符视为普通文本字符,可以用反斜杠来禁止元字符被解释扩展。
$ ls
# abc file1 youx
$ echo how are you?
# how are youx
$ echo how are you\?
# how are you?
$ echo when does this line \
> ever end\?
# when does this line ever end? 通过添加前导反斜杠来转义换行符。
波浪号和Hyphen扩展 波浪字符被bash
shell采纳为路径扩展字符。波浪号本身代表用户主目录的全路径名。当把波浪号加在一个用户名前,则表示该用户的全路径名。
当波浪号后面跟着加号时,PWD(present workding
directory,代表当前工作目录)的值将替换波浪号所代表的的目录名,波浪号所代表的的目录名将被替换为先前的工作目录。OLDPWD指的是先前的工作目录。
$ echo ~
# /home/tony
$ echo ~jobs
# /home/jobs 表示jobs用户的家目录路径全名
$ pwd
# /home/jobs
$ cd /etc/
$ echo ~+
# 表示工作目录的全路径即/etc
$ echo ~-
# 表示先前工作目录的全路径/home/jobs
$ echo $OLDPWD
# 保存先前工作目录的值即/home/jobs
$ cd -
# 减号引用了先前工作目录,cd命令切换到并显示先前的工作目录
控制通配符 如果设置了bash noglob变量或者使用了带-f选项的set
命令,称为globbing的文件名替换就会被禁止。这意味着所有元字符将表示其自身,而不再被视为通配符。这可能在使用grep,sed或awk程序搜索含元字符的模式时非常有用。如果没有设置globbing,所有元字符必须用反斜杠进行转义以关闭通配解释。
内置shopt命令也支持控制globbing的选项.
$ set -o noglob or set -f
$ echo * ?? [] ~ $LOGNAME
# * ?? [] /home/tony tony 这里因为波浪线没有用于文件名扩展,因此还是会被继续扩展解释。
$ set +o noglob or set +f
# 继续开启文件名元字符扩展
$ shopt -s dotglob
# 开启点开头文件的匹配,默认情况下是关闭状态
$ echo *bash*
# 如果dotglob处于关闭状态,则会打印*bash*,如果开启了dotglob,则会文件名扩展,并且包含点开头的文件名
# 例如.bash_profile .profile .bashrc等隐藏文件
扩展文件名globbing 沿袭了Korn
shell的模式匹配,bash也有扩展的功能,允许正则表达式类型的语法,除非用shopt命令的extglob选项打开该功能,否则无法识别正则表达式操作符。
shopt -s extglob
扩展模式匹配表
正则表达式 | 含义 |
---|---|
abc?(2|1)1 | ?匹配括号里的零个或一个字符。竖线代表or条件;即2或9.匹配的是abc21.abc91或abc1 |
abc*([0-9]) | *匹配括号里的零个或多个字符。匹配以abc开头,接着是零个或多个数字的模式。比如abc, abc1234, abc3, abc2 |
abc+([0-9]) | +匹配括号里的一个或多个字符。匹配以abc开头,接着是一个或多个数字的模式。比如abc3,abc123 |
no@(one|ne) | @匹配括号里的一项.匹配noone或none |
no!(thing|where) | !匹配除了括号里模式的所有字符串。匹配no,nobody或noone,但不匹配nothing或nowhere |
$ shopt -s extglob
$ ls
# abc abc122 f1 f3 nonsense nothing one abc1 abc2 f2 none noone nowhere
$ ls abc?(1|2)
# abc1 abc2 abc
$ ls abc*([0-9])
# abc abc1 abc122 abc2
$ ls abc+([0-9])
# abc1 abc2 abc3
$ ls no@(thing|ne)
# nothing none
$ ls no!(thing)
# none nonsense noone nowhere