Grep

ls -l *.<sometthing> | 之間的差異wc -l 和 ls -l |grep <某事> |wc -l

  • January 16, 2020

我有一個包含大量文件列表的文件夾,我要數數。我正在做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 .jsonorgrep '\.json'或的字元串grep '[.]json'
  • Xjson是在每一行上尋找的。使用ls -l,您將列印文件名、使用者名、組名、符號連結的目標,所有這些都可能包含Xjson.
  • 文件名也可以包含除 0 和 of 之外的任何字節值/(連結目標可以包含/);包括換行符。因此,如果您有一個名為的文件xjson\nyjson,它是指向的符號連結ajson\nbjson,沒有-qls -l因為該文件將列印 3 行,所有這些都將包含Xjson. 如果某些文件名包含在目前語言環境中不構成有效字元的字節序列,您也可能會感到驚訝。
  • grep | wc -l一般可以換成grep -c.

ls -l *.json | wc -l更糟。除了 @L.ScottJohnson 已經註意到的arg 列表太長的潛在問題之外,還有:

  • 如果沒有非隱藏.json文件,你會得到0一個錯誤,zsh因為*.jsonglob 無法匹配。
  • 對於每個目錄類型的參數,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 "$#"

(並且文件列表在"$@"(排序)中)。

引用自:https://unix.stackexchange.com/questions/562229