我想循環遍歷目錄中的所有檔案。
文件的設定如下:
<Overall>4
other data
<Overall>2
other data
......
我有代碼:
for file in .dat;
do
awk 'x+=sub(/<Overall>/,""){y+=$0} END{print FILENAME, y/x}' $file
done
這會列印出檔案中值的平均值,但是我想要的是將腳本所在的目錄作為參數,並對目錄中的所有 .dat 檔案執行 awk 命令。
我嘗試過使用代碼:
for file in $1
但出現錯誤:
awk: cmd. line:1: fatal cannot open file `folder' for reading (No such file or directory)
除此之外,我還希望能夠將平均值的輸出從高到低排序。
答案1
兩種變體:
- 循環文件並
awk
為每個文件調用一次,或者 - 為腳本提供
awk
所有文件,讓它計算每個文件的平均值並在運行過程中進行報告。
對以下任何解決方案的結果進行排序可以透過將其輸出通過管道來完成
sort -k2,2rn
這對第二個欄位(平均值)進行反向數字排序。
第一個解決方案:
#!/bin/sh
for name in "$1"/*.dat; do
test -f "$name" || continue # skip non-files
awk -F '>' '/<Overall>/ { s+=$NF; n++ } END { print FILENAME, s/n }' "$name"
done
該腳本需要命令列上的目錄名稱作為第一個也是唯一一個命令列參數。該awk
腳本將查找包含字串 的所有行,並對該行上後的值Overall
求和(在 中)。最後,平均值與檔案名稱一起輸出。該變數保存我們在 中加入內容的次數。s
>
n
s
第二種解決方案(需要 GNU Awk):
#!/bin/sh
find "$1" -maxdepth 1 -type f -name '*.dat' \
-exec awk -F '>' '/<Overall>/ { s+=$NF; n++ } ENDFILE { print FILENAME, s/n; s=n=0 }' {} +
該腳本與第一個腳本一樣,需要一個目錄名稱作為其唯一的命令列參數。它用於一次find
執行awk
包含盡可能多的文件的腳本。.dat
該awk
腳本利用 GNU Awk 的ENDFILE
觸發器來輸出計算值,並在處理每個檔案後、開始讀取下一個檔案之前重設s
和變數。n
這也可以寫成
#!/bin/sh
awk -F '>' '/<Overall>/ { s+=$NF; n++ } ENDFILE { print FILENAME, s/n; s=n=0 }' "$1"/*.dat
但這依賴於"$1"/*.dat
不要擴展到太長的文件名清單(這也要求每個.dat
名稱都是常規文件,這是上面find
命令所保證的-type f
)。