因此,我有一個文字文件,需要從中提取特定行併計算特定列中數字出現的次數。我有大約 100 個這樣的文件。我可以透過小步驟完成它,但想使用 bash/ksh 完成它:
foreach i *h3
sed '4p;55p;77q;d' $i >> output.txt
end
^^^^這只會從每個 h3 檔案中提取我需要的行
awk '{print $6}' output.txt | grep 'P2' | wc -l
^^^這只會從output.txt中提取第6列併計算P2出現在第6列中的次數
有沒有辦法將所有這些合併到 bash/ksh 腳本中?
答案1
如果我理解正確的話:
- 您想要計算幾個檔案(名為 *h3)的第 4,55 行和 77 行的第 6 個欄位中的任何位置有多少次「P2」?
您可以使用 1 awk 來完成此操作:
awk '
( FNR==4 || FNR==55 || FNR==77 ) {
if ( $6 ~ "P2" ) { occurence++ }
}
END {
printf "There was: %d P2 ", occurence
printf " among the 6th field on lines 4,55 or 77 of the *h3 files\n"
}' *h3
注意:如果您想要精確匹配,請更改$6 ~ "P2"
為$6 == "P2"
(而不是 grep,就像您在自己的範例中使用的那樣,以便它也匹配:somethingP2otherthing
及其變體)
FNR = 檔案的記錄數 = 目前檔案的行數(即每個檔案的第一行從 1 重新開始)(目前檔案的名稱也可以透過內部變數 FILENAME 得知)
(NR = 這裡不起作用,因為它是自開始(不是自當前文件開始以來)讀取的(總)數量或記錄)
答案2
當然。這是一種方法
p2_count=0
for f in *h3; do
for ((n=1; n<=77; n++)); do
IFS= read -r line
if [[ $n == 4|55|77 ]]; then
echo "$line"
set -f
set -- $line
set +f
if [[ $6 == *P2* ]]; then
((p2_count++))
fi
fi
done < "$f"
done > output.txt
echo "saw P2 in 6th column $p2_count times"
答案3
或使用巴什單行:
for i in *h3; do sed '4p;55p;77q;d' $i | awk '{print $6}' | grep 'P2'; done | wc -l
或更短使用grep -c
:
for i in *h3; do sed '4p;55p;77q;d' $i | awk '{print $6}'; done | grep -c 'P2'
答案4
通常,當問題詢問“如何使用特定工具在 bash 循環中? ”,部分答案是“不要使用 bash 循環,使用(部分或全部)工具本身”。有時答案的一部分甚至是“不要使用那些工具,請使用這個”。
你想要的可以單獨完成awk
,不需要 shell 循環。或sed
或grep
或wc
:
awk 'BEGIN {OFS="\t"}
FNR ~ /^(4|10|17)$/ && $6 ~ /P2/ {count++}
ENDFILE { print FILENAME, count; count=0 }' *h3
筆記:文件結束 是 GNU 特有的awk
。它不適用於其他版本的awk
.
此版本還列印所有文件的累積總數:
awk 'BEGIN {OFS="\t"}
FNR ~ /^(4|10|17)$/ && $6 ~ /P2/ {count++; total++}
ENDFILE { print FILENAME, count; count=0 }
END { print "---", total,"total" }' *h3
該END{}
區塊列印總數,並粗略地嘗試將實際總數與恰好具有檔案名稱「total」的任何檔案區分開。它透過---
在第一個欄位中列印,然後列印總計,然後total
在第三個欄位中列印字串來實現此目的。這遠非完美,但在許多情況下已經足夠好了。這比wc
根本不嘗試好。