如何使用 sed、awk、grep 和 wc 格式化 bash 循环

如何使用 sed、awk、grep 和 wc 格式化 bash 循环

因此,我有一个文本文件,需要从中提取特定行并计算特定列中数字出现的次数。我有大约 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 循环。或sedgrepwc

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根本不尝试要好。

相关内容