我想知道如何使用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)
$ 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中处理它以与我声称应该重写的这个线程中的其他脚本进行比较的示例!