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