我想要一個將返回一個表的bash命令,其中每行是可讀的文件大小,行數和文件名。該表應按文件大小排序。人類可讀的文件大小和行數
我一直在努力做到這一點使用的du -hs
,wc -l
和sort -h
和find
的組合。
下面是我在哪裏:
find . -exec echo $(du -h {}) $(wc -l {}) \; | sort -h
我想要一個將返回一個表的bash命令,其中每行是可讀的文件大小,行數和文件名。該表應按文件大小排序。人類可讀的文件大小和行數
我一直在努力做到這一點使用的du -hs
,wc -l
和sort -h
和find
的組合。
下面是我在哪裏:
find . -exec echo $(du -h {}) $(wc -l {}) \; | sort -h
你的做法短期下跌不僅是因爲外殼擴展您的命令替換($(...)
)前面,但更根本的,因爲你不能傳遞外殼命令行直接至find
:
find
的-exec
動作只能調用外部公用事業與字面參數 - 支持的唯一非文字形參是表示手頭的文件名(多個){}
。
choroba's answer修復您通過眼前的問題在每次迭代中調用一個單獨的殼例如,爲了外殼命令來執行作爲字符串參數(-exec bash -c '...' \;
)被傳遞哪個。
雖然這工作(假設你通過{}
值作爲參數而不是在命令行字符串嵌入它),它也是相當低效,因爲多個子進程創建每個輸入文件。
(雖然是辦法有find
通(典型地)所有輸入文件到一個(典型地)單調用指定的外部工具的 - 即與終止子+
而非\;
,這是不這裏由於傳遞的命令行的性質的選項。)
一種高效且健壯的[1] 執行該孩子的數目最小化處理創建應該是這樣的:
注:我假設這裏GNU公用事業,由於使用的head -n -1
和sort -h
。
另外,我限制find
的輸出文件只(而不是目錄),因爲wc -l
僅適用於文件。
paste <(find . -type f -exec du -h {} +) <(find . -type f -exec wc -l {} + | head -n -1) |
awk -F'\t *' 'BEGIN{OFS="\t"} {sub(" .+$", "", $3); print $1,$2,$3}' |
sort -h -t$'\t' -k1,1
使用注意事項的-exec ... +
而非-exec ... \;
,這確保了通常所有輸入的文件名被傳送到單個調用到外部實用程序(如果不是所有的文件名適合於單一命令行,調用有效批處理以儘可能少的調用)。
wc -l {} +
總是輸出一條摘要行,其中head -n -1
去掉,但也在每行數後輸出文件名。
paste
組合來自每個命令(其各自的輸入端通過取代。<(...)
的處理被設置)成單個輸出流的行。
awk
命令然後從每行的末尾去除源自wc
的外部文件名。
最後,sort
命令由第一排序結果(-k1,1
)製表符分隔(-t$'\t'
)柱通過人類可讀的數字(-h
),如數字,du -h
輸出(例如,1K
)。
[1]與任何線取向處理,嵌入式換行符文件名不支持,但我不認爲這是一個現實世界的問題。
的問題是,你的shell解釋$(...)
,所以find
沒有得到他們。轉義它們對(\$\(du -h {}\)
)無效,因爲它們成爲命令的正常參數,而不是命令替換。
爲了它們解釋爲命令替換是調用一個新的外殼,無論是直接
find . -exec bash -c 'echo $(du -h {}) $(wc -l {})' \; | sort -h
,或者通過創建腳本,並從find
調用它。
是否有可能只顯示文件名一次? – Hatshepsut
@Hatshepsut:當然,使用'wc -l <{}'。 – choroba
不幸的是,這將打破文件名與嵌入式元字符,如空格(並可能與嵌入式globbing字符)。 要解決這個問題,你必須使用'find。 -exec bash -c'echo'$(du -h「$ 1」)$(wc -l <「$ 1」)「' - {} \; |然而,即使這解決了OP的直接問題並且非常短,但這種方法對於大型輸入文件集將執行得不好,因爲它會創建多個子進程_per filename_。 – mklement0
好吧,我也試過用find/-exec,但逃跑是地獄。具有外殼功能,它的工作原理非常簡單:
#!/bin/bash
function dir
{
du=$(du -sh "$1" | awk '{print $1}')
wc=$(wc -l < "$1")
printf "%10s %10s %s\n" $du $wc "${1#./}"
}
printf "%10s %10s %s\n" "size" "lines" "name"
OIFS=$IFS; IFS=""
find . -type f -print0 | while read -r -d $'\0' f; do dir "$f"; done
IFS=$OIFS
使用basishm閱讀它甚至可以使用nul終止符來保證安全。 IFS需要避免讀取來截斷文件名中的尾隨空白。
順便說一下:$'\0'
實際上並不奏效(與''
相同) - 但它使意圖清晰。
輸出示例:
size lines name
156K 708 sash
16K 64 hostname
120K 460 netstat
40K 110 fuser
644K 1555 dir/bash
28K 82 keyctl
2.3M 8067 vim
告訴我們你得到了什麼 – eckes
@eckes用非工作代碼編輯 – Hatshepsut