Files
我想遞歸地找到每個目錄中最大的文件
輸出將包括目錄名、文件名和文件大小。執行命令的每個目錄都有一個(最大文件)。
如果可能,該目錄中文件的平均大小也是如此。
目的是可以在目錄中查找比目錄中其他文件大得多的文件,以便可以替換它們
結合
find
併awk
允許計算平均值:find . -type f -printf '%s %h/%f\0'|awk 'BEGIN { RS="\0" } { SIZE=$1; for (i = 1; i <= NF - 1; i++) $i = $(i + 1); NF = NF - 1; DIR=$0; gsub("/[^/]+$", "", DIR); FILE=substr($0, length(DIR) + 2); SUMSIZES[DIR] += SIZE; NBFILES[DIR]++; if (SIZE > MAXSIZE[DIR] || !BIGGESTFILE[DIR]) { MAXSIZE[DIR] = SIZE; BIGGESTFILE[DIR] = FILE } }; END { for (DIR in SUMSIZES) { printf "%s: average %f, biggest file %s %d\n", DIR, SUMSIZES[DIR] / NBFILES[DIR], BIGGESTFILE[DIR], MAXSIZE[DIR] } }'
以更易讀的方式佈局,AWK 腳本是
BEGIN { RS="\0" } { SIZE=$1 for (i = 1; i <= NF - 1; i++) $i = $(i + 1) NF = NF - 1 DIR=$0 gsub("/[^/]+$", "", DIR) FILE=substr($0, length(DIR) + 2) SUMSIZES[DIR] += SIZE NBFILES[DIR]++ if (SIZE > MAXSIZE[DIR] || !BIGGESTFILE[DIR]) { MAXSIZE[DIR] = SIZE BIGGESTFILE[DIR] = FILE } } END { for (DIR in SUMSIZES) { printf "%s: average %f, biggest file %s %d\n", DIR, SUMSIZES[DIR] / NBFILES[DIR], BIGGESTFILE[DIR], MAXSIZE[DIR] } }
這需要空值分隔的輸入記錄(我從muru 的回答中偷了這個);對於每個輸入記錄,它
- 儲存大小(供以後使用),
- 刪除路徑中第一個字元之前的所有內容(因此我們至少可以正確處理帶有空格的文件名),
- 提取目錄,
- 提取文件名,
- 將我們之前儲存的大小添加到目錄中的大小總和中,
- 增加目錄中的文件數(因此我們可以計算平均值),
- 如果大小大於目錄的儲存最大大小,或者我們還沒有在目錄中看到文件,則更新最大文件的資訊。
完成所有這些後,腳本會遍歷輸入的鍵
SUMSIZES
並輸出目錄、平均大小、最大文件的名稱和大小。您可以將輸出通過管道輸入
sort
以按目錄名稱排序。如果您想另外以人類友好的形式格式化尺寸,您可以將printf
行更改為printf "%.2f %d %s: %s\n", SUMSIZES[DIR] / NBFILES[DIR], MAXSIZE[DIR], DIR, BIGGESTFILE[DIR]
然後將輸出通過管道傳輸到
numfmt --field=1,2 --to=iec
. 您仍然可以按目錄名稱對結果進行排序,您只需要從第三個欄位開始排序:sort -k3
.
使用 GNU
find
和(4.2.2 或更高版本),按文件大小排序一次,然後按目錄路徑排序sort
:sed
find /some/dir -type f -printf '%s %f%h\0' | sort -zrn | sort -zut/ -k2 | sed -zre 's: ([^/]*)(/.*): \2/\1:'
解釋:
- 列印文件大小、名稱和路徑(第一個由空格分隔,接下來的兩個由 分隔
/
),每個條目都以 ASCII NUL 字元終止。- 然後我們使用大小進行數字排序,假設 NUL 分隔的輸出(並且以相反的順序,所以最大的文件在前)。
- 然後我們使用
sort
第二個分隔欄位中的所有內容僅列印第一個唯一條目/
,該欄位將是包含文件的目錄的路徑。- 然後我們
sed
用來交換目錄和文件名,這樣我們就得到了一個正常的路徑。對於可讀輸出,將 ASCII NUL 替換為換行符:
find /some/dir -type f -printf '%s %f%h\0' | sort -zrn | sort -zut/ -k2 | sed -zre 's: ([^/]*)(/.*): \2/\1:' | tr '\0' '\n'
範例輸出:
$ find /var/log -type f -printf '%s %f%h\0' | sort -zrn | sort -zt/ -uk2 | sed -zre 's: ([^/]*)(/.*): \2/\1:' | tr '\0' '\n' 3090885 /var/log/syslog.1 39789 /var/log/apt/term.log 3968 /var/log/cups/access_log.1 31 /var/log/fsck/checkroot 467020 /var/log/installer/initial-status.gz 44636 /var/log/lightdm/seat0-greeter.log 15149 /var/log/lxd/lxd.log 4932 /var/log/snort/snort.log 3232 /var/log/unattended-upgrades/unattended-upgrades-dpkg.log