Zsh 開發指南(第十篇 文件查找和批量處理)

導讀

尋找知足特定條件的文件路徑,簡稱文件查找,是 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複製代碼

這樣就能夠更方便地使用計算器了。

總結

本文介紹了文件查找中的通配符修飾語的用法,而且列出來大多數經常使用的通配符修飾語,還有一小部分更復雜或者更少用的暫時空缺,之後可能會補上。這些通配符修飾語沒有必要所有記下來,熟悉經常使用的,其他的等用的時候再查詢便可。

參考

www.bash2zsh.com/zsh_refcard…

blog.sina.com.cn/s/blog_687b…

更新歷史

2017.08.31:增長「不展開通配符」和「文件批量重命名」。

全系列文章地址:github.com/goreliu/zsh…

付費解決 Windows、Linux、Shell、C、C++、AHK、Python、JavaScript、Lua 等領域相關問題,靈活訂價,歡迎諮詢,微信 ly50247。

相關文章
相關標籤/搜索