awk总结出多个文件显示的行不出现在两组文件上

我一直在使用awk来总结多个文件,这是用来总结服务器日志parsing值的总结,它确实加快了最终的总体计数,但是我遇到了一个小问题,我碰到的典型例子是networking没有帮助。

这是一个例子:

cat file1 aa 1 bb 2 cc 3 ee 4 cat file2 aa 1 bb 2 cc 3 dd 4 cat file3 aa 1 bb 2 cc 3 ff 4 

和脚本:

 cat test.sh #!/bin/bash files="file1 file2 file3" i=0; oldname=""; for names in $(echo $files); do ((i++)); if [ $i == 1 ]; then oldname=$names #echo "-- $i $names" shift; else oldname1=$names.$$ awk 'NR==FNR { _[$1]=$2 } NR!=FNR { if(_[$1] != "") nn=0; nn=($2+_[$1]); print $1" "nn }' $names $oldname> $oldname1 if [ $i -gt 2 ]; then rm $oldname; fi oldname=$oldname1 fi done echo "------------------------------ $i" cat $oldname 

当我运行这个,相同的列加起来,但只出现在其中一个文件中没有

 ./test.sh ------------------------------ 3 aa 3 bb 6 cc 9 ee 4 

dd没有出现在列表中,从我在NR == FR中看到的

我碰到过这个:

http://dbaspot.com/shell/246751-awk-comparing-two-files-problem.html

 you want all the lines in file1 that are not in file2, awk 'NR == FNR { a[$0]; next } !($0 in a)' file2 file1 If you want only uniq lines in file1 that are not in file2, awk 'NR == FNR { a[$0]; next } !($0 in a) { print; a[$0] }' file2 file1 

但是这样做只会使当前的问题更加复杂,因为许多其他领域都会被重复

发布问题后 – 更新内容…和testing….

我想坚持awk,因为它似乎是一个更短的方法来实现结果还有一个问题。

 awk '{a[$1]+=$2}END{for (k in a) print k,a[k]}' file1 file2 file3 aa 3 bb 6 cc 9 ee 4 ff 4 gg 4 RESULT_SET_4 0 RESULT_SET_3 0 RESULT_SET_2 0 RESULT_SET_1 0 $ cat file1 RESULT_SET_1 aa 1 RESULT_SET_2 bb 2 RESULT_SET_3 cc 3 RESULT_SET_4 ff 4 $ cat file2 RESULT_SET_1 aa 1 RESULT_SET_2 bb 2 RESULT_SET_3 cc 3 RESULT_SET_4 ee 4 

文件内容不是原来的,即结果不在标题下,我的原始方法确实保持了原样

更新预期的输出 – 正确的上下文中的标题

 cat file1 RESULT_SET_1 aa 1 RESULT_SET_2 bb 2 RESULT_SET_3 cc 3 RESULT_SET_4 ff 4 cat file2 RESULT_SET_1 aa 1 RESULT_SET_2 bb 2 RESULT_SET_3 cc 3 RESULT_SET_4 ee 4 cat file3 RESULT_SET_1 aa 1 RESULT_SET_2 bb 2 RESULT_SET_3 cc 3 RESULT_SET_4 gg 4 test.sh awk line to produce above is : awk -vi=$i 'NR==FNR { _[$1]=$2 } NR!=FNR { if (_[$1] != "") { if ($2 ~ /[0-9]/) { nn=($2+_[$1]); print $1" "nn; } else { print;} }else { print; } }' $names $oldname> $oldname1 ./test.sh ------------------------------ 3 RESULT_SET_1 aa 3 RESULT_SET_2 bb 6 RESULT_SET_3 cc 9 RESULT_SET_4 ff 4 

工程,但破坏所需的格式

  awk '($2 != "") {a[$1]+=$2}; ($2 == "") { a[$1]=$2 } END {for (k in a) print k,a[k]} ' file1 file2 file3 aa 3 bb 6 cc 9 ee 4 ff 4 gg 4 RESULT_SET_4 RESULT_SET_3 RESULT_SET_2 RESULT_SET_1 

 $ awk '{a[$1]+=$2}END{for (k in a) print k,a[k]}' file1 file2 file3 | sort aa 3 bb 6 cc 9 dd 4 ee 4 ff 4 

编辑:

这是一个黑客,但它的工作:

 $ awk 'FNR==NR&&!/RESULT/{a[$1]=$2;next}($1 in a){a[$1]+=$2}END{for (k in a) print k,a[k]}' file1 file2 file3 | sort | awk '$1="RESULTS_SET_"NR"\n"$1' RESULTS_SET_1 aa 3 RESULTS_SET_2 bb 6 RESULTS_SET_3 cc 9 RESULTS_SET_4 ff 4 

你可以在awk这样做,就像sudo_O建议的那样,但是你也可以用纯粹的bash来做到这一点。

 #!/bin/bash # We'll use an associative array, where the indexes are strings. declare -A a # Our list of files, in an array (not associative) files=(file1 file2 file3) # Walk through array of files... for file in "${files[@]}"; do # And for each file, increment the array index with the value. while read index value; do ((a[$index]+=$value)) done < "$file" done # Walk through array. ${!...} returns a list of indexes. for i in ${!a[@]}; do echo "$i ${a[$i]}" done 

结果是:

 $ ./doit dd 4 aa 3 ee 4 bb 6 ff 4 cc 9 

如果你想输出排序…你可以通过sort管道。 🙂

这是使用GNU awk的一种方法。 运行如下:

 awk -f script.awk File1 File2 File3 

script.awk内容:

 sub(/RESULT_SET_/,"") { i = $1 next } { a[i][$1]+=$2 } END { for (j=1;j<=length(a);j++) { print "RESULT_SET_" j for (k in a[j]) { print k, a[j][k] } } } 

结果:

 RESULT_SET_1 aa 3 RESULT_SET_2 bb 6 RESULT_SET_3 cc 9 RESULT_SET_4 ee 4 ff 4 gg 4 

另外,这里是一行:

 awk 'sub(/RESULT_SET_/,"") { i = $1; next } { a[i][$1]+=$2 } END { for (j=1;j<=length(a);j++) { print "RESULT_SET_" j; for (k in a[j]) print k, a[j][k] } }' File1 File2 File3 

固定使用这基本上是通过每个文件,如果条目存在于另一边,它将添加条目近似行号为0值,以便它可以总结内容 – 已经测试了我目前的输出,似乎工作真的很好

 #!/bin/bash files="file1 file2 file3 file4 file5 file6 file7 file8" RAND="$$" i=0; oldname=""; for names in $(echo $files); do ((i++)); if [ $i == 1 ]; then oldname=$names shift; else oldname1=$names.$RAND for entries in $(awk -vi=$i 'NR==FNR { _[$1]=$2 } NR!=FNR { if (_[$1] == "") { if ($2 ~ /[0-9]/) { nn=0; nn=(_[$1]+=$2); print FNR"-"$1"%0"} else { } } else { } }' $oldname $names); do line=$(echo ${entries%%-*}) content=$(echo ${entries#*-}) content=$(echo $content|tr "%" " ") edit=$(ed -s $oldname << EOF $line a $content . w q EOF ) $edit >/dev/null 2>&1 done awk -vi=$i 'NR==FNR { _[$1]=$2 } NR!=FNR { if (_[$1] != "") { if ($2 ~ /[0-9]/) { nn=0; nn=($2+_[$1]); print $1" "nn; } else { print $1;} }else { print; } }' $names $oldname> $oldname1 oldname=$oldname1 fi done cat $oldname #rm file?.*