ls -l *.<sometthing> | 之間的差異wc -l 和 ls -l |grep <某事> |wc -l
我有一個包含大量文件列表的文件夾,我要數數。我正在做
ls -l *.json | wc -l
並且工作正常,直到列表顯然變得足夠大以至於該命令不再起作用。我後來試過了
ls -l | grep .json | wc -l
,它就像一個魅力。所以我想知道兩者有什麼區別?我認為這是因為後者不是
ls
一次所有文件,而是將文件連續流式傳輸到grep
然後到wc
?是這樣,還是工作方式不同?
如果要計算
.json
目前目錄中具有副檔名的非隱藏文件的數量,可以這樣做:(){echo $#} *.json(NoN)
(
N
對於nullglob
,oN
禁用我們在這裡不需要的排序)。
ls -l | grep .json | wc -l
錯誤的原因有很多:
.
是匹配任何單個字元的正則表達式運算符。如果您想搜尋.json
將是grep -F .json
orgrep '\.json'
或的字元串grep '[.]json'
。- 這
Xjson
是在每一行上尋找的。使用ls -l
,您將列印文件名、使用者名、組名、符號連結的目標,所有這些都可能包含Xjson
.- 文件名也可以包含除 0 和 of 之外的任何字節值
/
(連結目標可以包含/
);包括換行符。因此,如果您有一個名為的文件xjson\nyjson
,它是指向的符號連結ajson\nbjson
,沒有-q
,ls -l
因為該文件將列印 3 行,所有這些都將包含Xjson
. 如果某些文件名包含在目前語言環境中不構成有效字元的字節序列,您也可能會感到驚訝。grep | wc -l
一般可以換成grep -c
.
ls -l *.json | wc -l
更糟。除了 @L.ScottJohnson 已經註意到的arg 列表太長的潛在問題之外,還有:
- 如果沒有非隱藏
.json
文件,你會得到0
一個錯誤,zsh
因為*.json
glob 無法匹配。- 對於每個目錄類型的參數,
ls -l
列出它們的內容,所以如果你有一個dir.json
目錄,那麼它列出的所有行都將被計算在內。通常,您希望-d
在將全域擴展傳遞給ls
.- 如果任何文件名
.json
以.-``ls``ls
- 像上面一樣,如果文件名或符號連結目標包含換行符,您將遇到問題。
您可以通過以下方式修復大多數問題:
LC_ALL=C ls -qd -- *.json | wc -l
但是在那裡,所有的實際工作都是由 shell 完成的。shell 是擴展
*.json
匹配文件列表並將其傳遞給ls
.ls
僅用於在單獨的行上列印每個以供輸入,wc
以便對其進行計數。ls
還做了很多不必要的工作,比如stat()
對每個進行系統呼叫以檢查它是否存在(使用-l
,它對lstat()
使用者/組名稱解析執行 a 和一些 uid/gid,readlink()
對符號連結執行 s),並再次對列表進行排序( shell 已經對*.json
擴展進行了排序)。外殼本身能夠很好地計算該擴展。
使用
(){echo $#} *.json(NoN)
,我們使用匿名函式,您也可以使用臨時數組:files=(*.json(NoN)); echo $#files
。另請注意,它只需要讀取目前目錄的內容來建構該列表,它不需要像這樣
ls
做那樣嘗試單獨查找每個文件。請注意,該語法特定於
zsh
. POSIX 中的等價物sh
類似於:set -- [*].json *.json case $1$2 in ('[*].json*.json') shift 2;; (*) shift;; esac echo "$#"
(並且文件列表在
"$@"
(排序)中)。