如何使用Awk或Bash在1个文件中组合具有相同标头的列

taf*_*kje 1 bash awk

我想知道如何使用bash/sed/awk将列与重复标题组合在一起.

   x y  x  y
s1 3 4  6 10
s2 3 9 10  7
s3 7 1  3  2
Run Code Online (Sandbox Code Playgroud)

至 :

    x  y
s1  9 14
s2 13 16
s3 10  3
Run Code Online (Sandbox Code Playgroud)

Ed *_*ton 5

$ cat file
   x y  x  y
s1 3 4  6 10
s2 3 9 10  7
s3 7 1  3  2

$ cat tst.awk
NR==1 {
   for (i=1;i<=NF;i++) {
      flds[$i] = flds[$i] " " i+1
   }
   printf "%-3s",""
   for (hdr in flds) {
      printf "%3s",hdr
   }
   print ""
   next
}
{
   printf "%-3s",$1
   for (hdr in flds) {
      n = split(flds[hdr],fldNrs)
      sum = 0
      for (i=1; i<=n; i++) {
         sum += $(fldNrs[i])
      }
      printf "%3d",sum
   }
   print ""
}

$ awk -f tst.awk file
     x  y
s1   9 14
s2  13 16
s3  10  3

$ time awk -f ./tst.awk file
     x  y
s1   9 14
s2  13 16
s3  10  3

real    0m0.265s
user    0m0.030s
sys     0m0.108s
Run Code Online (Sandbox Code Playgroud)

如果您愿意,可以以明显的方式调整printf行以进行不同的输出格式.

这是响应注释elsethread的bash等价物.不要使用它,awk解决方案是正确的,这只是为了展示你应该如何在bash中编写它如果你想出于某种莫名的原因这样做:

$ cat tst.sh
declare -A flds
while IFS= read -r rec
do
   lineNr=$(( lineNr + 1 ))
   set -- $rec

   if (( lineNr == 1 ))
   then

      fldNr=1
      for fld
      do
         fldNr=$(( fldNr + 1 ))
         flds[$fld]+=" $fldNr"
      done
      printf "%-3s" ""
      for hdr in "${!flds[@]}"
      do
         printf "%3s" "$hdr"
      done
      printf "\n"

   else

      printf "%-3s" "$1"
      for hdr in "${!flds[@]}"
      do
         fldNrs=( ${flds[$hdr]} )
         sum=0
         for fldNr in "${fldNrs[@]}"
         do
            eval val="\$$fldNr"
            sum=$(( sum + val ))
         done
         printf "%3d" "$sum"
      done
      printf "\n"

   fi

done < "$1"
$
$ time ./tst.sh file
     x  y
s1   9 14
s2  13 16
s3  10  3

real    0m0.062s
user    0m0.031s
sys     0m0.046s
Run Code Online (Sandbox Code Playgroud)

请注意,它与awk脚本的运行时间大致相同(参见注释elsethread).警告 - 我从来没有写过用于处理文本文件的bash脚本,所以我没有声称上面的bash脚本是完美的,只是一个如何在bash中处理它以与我声称应该重写的这个线程中的其他脚本进行比较的示例!