Zsh 开发指南(第十篇 文件查找和批量处理)

导读

寻找满足特定条件的文件路径,简称文件查找,是 shell 脚本的常见任务,因为条件复杂多样,这样的任务并不轻松。很多人使用 find 命令来做,但 find 只能覆盖一部分功能,其他的要自己进一步处理,而且 find 并不好用,和脚本其他部分配合也比较麻烦,容易出错。用 zsh 的话,基本不需要 find 命令,借助 zsh 自身的功能便足以应付多数场景,而且语法更优雅简洁不易出错。

简单例子

列出 /usr/bin 目录下以 zsh 开头的文件。

# 加 -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 非常常用。

删除 /tmp 下所有的形如 abc1234.tmp(前边字母后边数字,个数不限,但至少有一个字母一个数字)的文件,包括子目录里的。

% setopt EXTENDED_GLOB
# /**/ 是递归搜索文件
# ## 是前边的内容至少重复一次,<-> 是任何整数或 0
% rm -v /tmp/**/[a-zA-Z]##<->.tmp
removed '/tmp/yaourt-tmp-goreliu/abc123.tmp'

setopt EXTENDED_GLOB 是启用扩展的通配符支持,本文后续的内容默认该选项已开启,不然通配符功能太弱,建议写到 .zshrc 里边。通配符的内容之前已经讲过,可以当手册参考。

两个小例子热完身后开始进入正题。

按文件属性查找

除了匹配文件路径外,很多时候我们还需要按文件属性查找,比如根据文件类型、权限、大小、修改时间等等。这里需要使用一个新东西,通配符修饰语。

先举个例子看看它的样子。列出当前目录及子目录中的所有普通文件(即 ls -l 结果中第一位是 - 的文件,非目录、符号链接、设备文件、socket、FIFO 等等)。

% print -l **/*(.)
a.txt
b/htm

这里比之前的例子多了个末尾的小括号,里边有一个点。这个小括号及里边的内容便是通配符修饰语,专门用于按文件属性来匹配文件。点(.)代表普通文件。

更多例子:

# 列出当前目录下的非空目录,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_refcard/refcard.pdf

http://blog.sina.com.cn/s/blog_687bd5d50101epna.html

更新历史

2017.08.31:增加“不展开通配符”和“文件批量重命名”。

本文不再更新,全系列文章在此更新维护:github.com/goreliu/zshguide

付费解决 Windows、Linux、Shell、C、C++、AHK、Python、JavaScript、Lua 等领域相关问题,灵活定价,欢迎咨询,微信 ly50247。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 218,204评论 6 506
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,091评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,548评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,657评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,689评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,554评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,302评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,216评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,661评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,851评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,977评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,697评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,306评论 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,898评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,019评论 1 270
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,138评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,927评论 2 355

推荐阅读更多精彩内容

  • Ubuntu的发音 Ubuntu,源于非洲祖鲁人和科萨人的语言,发作 oo-boon-too 的音。了解发音是有意...
    萤火虫de梦阅读 99,271评论 9 467
  • Linux命令学习 记录小白学习Linux的过程。 常用命令 man命令 常用工具命令 man命令是Linux下的...
    吃蘑菇De大灰狼阅读 2,752评论 1 15
  • linux资料总章2.1 1.0写的不好抱歉 但是2.0已经改了很多 但是错误还是无法避免 以后资料会慢慢更新 大...
    数据革命阅读 12,168评论 2 33
  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,657评论 18 139