寻找知足特定条件的文件路径,简称文件查找,是 shell 脚本的常见任务,由于条件复杂多样,这样的任务并不轻松。不少人使用 find 命令来作,但 find 只能覆盖一部分功能,其余的要本身进一步处理,并且 find 并很差用,和脚本其余部分配合也比较麻烦,容易出错。用 zsh 的话,基本不须要 find 命令,借助 zsh 自身的功能便足以应付多数场景,并且语法更优雅简洁不易出错。html
列出 /usr/bin 目录下以 zsh 开头的文件。git
# 加 -l 为了换行显示更易读,若是须要操做这些文件,将 print -l 换成其余命令便可 % print -l /usr/bin/zsh* /usr/bin/zsh /usr/bin/zsh-5.4.1 /usr/bin/zshdb
有人可能会说用 ls /usr/bin/zsh 就行。若是用 ls 的话,就平添了很多额外工做,由于 zsh 已经匹配一次文件路径,结果出来了,传给 ls 后,ls 又去 stat 了一下那些文件,而这彻底是多余工做,若是文件列表长的话,要多消耗很多时间。不少看起来理所固然的 shell 用法都存在相似这样的问题。因此打命令或者写脚本时,不能看结果正确就能够了,要知其因此然。若是嫌 print -l 太长,alias 个 pl 就能够了,print -l 很是经常使用。github
删除 /tmp 下全部的形如 abc1234.tmp(前边字母后边数字,个数不限,但至少有一个字母一个数字)的文件,包括子目录里的。shell
% setopt EXTENDED_GLOB # /**/ 是递归搜索文件 # ## 是前边的内容至少重复一次,<-> 是任何整数或 0 % rm -v /tmp/**/[a-zA-Z]##<->.tmp removed '/tmp/yaourt-tmp-goreliu/abc123.tmp'
setopt EXTENDED_GLOB 是启用扩展的通配符支持,本文后续的内容默认该选项已开启,否则通配符功能太弱,建议写到 .zshrc 里边。通配符的内容以前已经讲过,能够当手册参考。bash
两个小例子热完身后开始进入正题。微信
除了匹配文件路径外,不少时候咱们还须要按文件属性查找,好比根据文件类型、权限、大小、修改时间等等。这里须要使用一个新东西,通配符修饰语。socket
先举个例子看看它的样子。列出当前目录及子目录中的全部普通文件(即 ls -l 结果中第一位是 - 的文件,非目录、符号连接、设备文件、socket、FIFO 等等)。ide
% print -l **/*(.) a.txt b/htm
这里比以前的例子多了个末尾的小括号,里边有一个点。这个小括号及里边的内容即是通配符修饰语,专门用于按文件属性来匹配文件。点(.)表明普通文件。函数
更多例子:ui
# 列出当前目录下的非空目录,F 是空的意思 % print -l *(/F) # 列出当前目录下的空目录,^ 是取反 % print -l *(/^F) # 列出当前目录下的符号连接文件和可执行的普通文件,多种文件类型用逗号隔开 % print -l *(@,.x) # 列出符合 0644 权限的普通文件 % print -l *(.f0644)
那么咱们来看下都有哪些可用的通配符修饰语,而后再举更复杂的例子。
名称 | 含义 | 使用样例或补充说明 | |
---|---|---|---|
/ | 目录 | ||
F | 非空 | /F(空目录) /^F(非空目录) | |
. | 普通文件 | ||
@ | 符号连接 | ||
= | socket 文件 | ||
p | FIFO 文件 | ||
* | 可执行的普通文件 | ||
% | 设备文件 | ||
%b | 块设备文件 | ||
%c | 字符设备文件 | ||
r | 文件拥有着有读权限 | ||
w | 文件拥有着有写权限 | ||
x | 文件拥有着有执行权限 | ||
A | 文件拥有组用户有读权限 | ||
I | 文件拥有组用户有写权限 | ||
E | 文件拥有组用户有执行权限 | ||
R | 任何用户都有读权限 | ||
W | 任何用户都有写权限 | ||
X | 任何用户都有执行权限 | ||
s | 设置了 setuid 的文件 | ||
S | 设置了 setgid 的文件 | ||
t | 设置了粘滞位(sticky bit)的文件 | ||
f | 符合指定的权限 | f0644 f4755 f700 | |
e | 内容待更新 | ||
+ | 内容待更新 | ||
d | 指定设备号 | ||
l | 硬链接个数 | l-2(小于 2) l+3(大于 3) | |
U | 当前用户拥有 | ||
G | 当前用户所在组拥有 | ||
u | 指定用户 id 拥有 | u1000 | |
g | 指定用户组 id 拥有 | g1000 | |
a | 指定文件的 atime | 下文有说明 | |
m | 指定文件的 mtime | 下文有说明 | |
c | 指定文件的 ctime | 下文有说明 | |
L | 指定文件大小 | 下文有说明 | |
^ | 取反 | /^F | |
- | 内容待更新 | ||
M | 内容待更新 | ||
T | 内容待更新 | ||
N | 若是没匹配到,返回空而不报错 | ||
D | 包含隐藏文件(. 开头) | ||
n | 按数值大小排序 | 下文有说明 | |
o | 递增排序 | 下文有说明 | |
O | 递减排序 | 下文有说明 | |
[n] | 只取前 n 个文件 | .[5] | |
[n1,n2] | 取第 n1 到 n2 个文件 | /[5,10] | |
:X | 内容待更新 |
# 列出最近一天修改过内容的文件 % print -l *(.m-1) # 列出最近一个月没有读取过的文件 % print -l *(.aM+1)
m 后边可加单位,若是没有单位,默认是天。其余单位:M(月)、w(周)、h(小时)、m(分钟)、s(秒)。+ 是指定时间以前,- 是指定时间以内。
a 是最后访问时间(atime),但注意若是分区挂载时指定了 noatime 或者 realtime(能够查看 /proc/mount 确认),那么 atime 并非真正的最后访问时间。m 是最后修改时间(mtime),这里指内容修改,而不包括文件属性(如权限)的修改。c 是最后状态修改时间(ctime),若是文件内容没有修改,而文件属性发生变化,这个时间会更新。若是不能理解请在网上搜索相关文章。
# 列出当前目录下小于 2k 的文件 % print -l *(.Lk-2) # 列出当前目录下大于 1m 的文件 % print -l *(.Lm+1) # 注意这样只能找到空文件,由于以 m 为单位的话,文件只能是 0 m 或者 1 m,不能 0.5 m # 因此比 1 小就是 0 m,是空文件 % print -l *(.Lm-1)
默认的单位是字节,还可使用 k、m 和 p(512 字节的块),也可使用大写的 K、M、P,含义同样。
# 按文件名排序,同一目录下的文件和目录名会一块儿排,而不是先排目录再排文件 % print -l **/*(.on) bb.txt cc/aa.txt cc/dd.txt zz.txt # 按文件的目录深度逆序排,d 是从深往浅排,O 是逆序 % print -l **/*(.Od) zz.txt bb.txt cc/dd.txt cc/aa.txt # 先按文件名排序,而后再按大小排序,这样大小相同的文件依然是按文件名排的 % print -l **/*(.onoL) bb.txt cc/aa.txt cc/dd.txt cc.txt
像第三个例子那样,能够排屡次。
可供排序的因素:n(文件名,若是不指定排序选项,默认按文件名排,即 on)、L(大小)、l(硬链接数)、a(atime)、m(mtime)、c(ctime)、d(所在目录深度,从深到浅排)。
如今咱们大概了解了都有哪些可供使用的通配符修饰语,单个使用已经没有什么问题了。但若是同时使用多个,就涉及到怎么组合在一块儿的问题。
类型和类型之间要用逗号隔开,若是不指定类型,表明全部类型均可以,逗号先后的内容互不干扰(取反 ^ 操做只影响到逗号以前内容)。同一个类型能够同时加多个选项,依次添加便可。
# 当前目录下的两天内修改过的目录 # 加上小于 3 m 的普通文件从小到大排 # 再加上全部的符号连接文件(包括隐藏文件) % print -l *(/m-2,.Lm-3oL,@D)
对文件进行批量重命名,是一个比较常见的场景。Zsh 中有一个很是方便的命令 zmv,它可让批量重命名变得很简单。
# 使用前须要先加载进来 % autoload -U zmv # 将全部 txt 文件扩展名改为 conf # 参数要用单引号扩起来,$1 表明第一个参数中括号中的内容 % zmv '(*).txt' '$1.conf' # 若是加了 -W 参数,zmv 会自动识别文件名中须要保留的部分 % zmv -W '*.txt' '*.conf' # 调整文件名各部分的先后顺序 % zmv '(*).(*).txt' '$2.$1.txt' # 加 -n 预览而不实际运行 % zmv -n '(*).(*).txt' '$2.$1.txt' mv -- a.b.txt b.a.txt # 0 1 2 ... 前添加 0,以便和 10 11 12 ... 宽度一致 % zmv '([0-9]).(*)' '0$1.$2' # 去掉开头的一个 0 % zmv '(0)(*)' '$2' # 文件整理到目录 % zmv '(*) - (*) - (*).txt' '$1/$2 - $3.txt' # 转换大小写 % zmv '(*).txt' '${(U)1}.txt' % zmv '(*).txt' '${(L)1}.txt'
有时咱们不想展开通配符,好比我写了一个计算的函数叫作 calc:
calc() { zmodload zsh/mathfunc echo $(($*)) } % calc 12+12 24
但若是我想计算 12 * 12:
% calc 12*12 zsh: no matches found: 12*12
若是不加引号的话,星号会被做为通配符使用,而后去找符合 12*12 的文件名,没找到全部报错了。但我并不想找文件。
noglob 命令能够禁止展开后边内容的通配符,这样就不须要加引号了。
% noglob calc 12*12 144
而后能够写个 alias:
% alias js="noglob calc" % js 12*12 144
这样就能够更方便地使用计算器了。
本文介绍了文件查找中的通配符修饰语的用法,而且列出来大多数经常使用的通配符修饰语,还有一小部分更复杂或者更少用的暂时空缺,之后可能会补上。这些通配符修饰语没有必要所有记下来,熟悉经常使用的,其他的等用的时候再查询便可。
http://www.bash2zsh.com/zsh_r...
http://blog.sina.com.cn/s/blo...
2017.08.31:增长“不展开通配符”和“文件批量重命名”。
本文再也不更新,全系列文章在此更新维护:github.com/goreliu/zshguide
付费解决 Windows、Linux、Shell、C、C++、AHK、Python、JavaScript、Lua 等领域相关问题,灵活订价,欢迎咨询,微信 ly50247。