如何将每两行合并为一行,缺少数据并保持不变?

时间:2012-09-20 21:07:32

标签: awk

我有一个2N行的多列文件,它由0s,1s和缺失数据组成(编码为“?”)。它看起来像这样:

1 0 0 ? 1 ?
1 ? 1 ? 1 1
1 0 1 ? 1 1
0 ? 0 1 0 ?
0 0 1 ? 0 0
0 0 0 ? 0 ?
0 ? 0 0 1 1
1 1 1 1 1 1          

我想总结每两行并输出一个N行文件。如果有“?”连续输出应该是“?”对于该特定字段(?+0 =?+ 1 =?+?=?)。所以我的例子的输出将如下所示:

2 ? 1 ? 2 ?
1 ? 1 ? 1 ?
0 0 1 ? 0 ?
1 ? 1 1 2 2

我尝试了这段代码,但似乎在计算时将丢失的数据视为“0”。有没有办法将丢失的数据保持为“?” ?

cat <input_file> |awk -F ' ' '{if (NR%2==1){for(j=1;j<=NF;j++)array[j]=$j;}else{result="";for(i=1;i<=NF;i++){tmp=array[i]+$i;result=sprintf("%s%d ",result,tmp);}print result;}}' > <output_file>

请帮忙。任何建议将不胜感激!

3 个答案:

答案 0 :(得分:3)

我担心您必须将每个字段与"?"进行比较:

< input_file  awk '
NR%2 { split($0,saved,FS) }      # save odd line fields
NR%2 == 0 {                      # on even lines:
  for(i=1; i<=NF; i++){
    $i = $i=="?"       ? "?" :   #  "?" if this line field is "?"
         saved[i]=="?" ? "?" :   #  "?" if the previous line field was "?"
         saved[i]+$i             #  the sum otherwise
  }
  print
}'

答案 1 :(得分:3)

只能在一个(bash)shell中完成:

while read line; do 
    set -- $line
    read line
    ary=( $line )
    i=0
    for arg; do     
        if [ "$arg" = "?" -o "${ary[i]}" = "?" ]; then          
            printf "? "     
        else
            printf "%d " $(( $arg + ${ary[i]} ))     
        fi     
        ((i++)) 
    done 
    printf "\n"
done < file
用awk,我写了类似的东西

awk '{ 
    getline nextline
    split(nextline, ary)
    for (i=1; i<=NF; i++) {
        if ($i == "?" || ary[i] == "?")
            printf("? ")
        else
            printf("%d ", $i + ary[i])
    }
    print ""
}' file

答案 2 :(得分:1)

> cat temp.awk
{
if(NR%2==1)
 {
  split($0,a," ");
 }
 else
 {
 line="";
 for(i=1;i<=NF;i++)
 {
  a[i]=="?"||$i=="?" ? sum="?":sum=a[i]+$i;
  line=line" "sum;
 }
 print line; 
 }
}

创建上面的awk脚本后,使用以下命令:

awk -f temp.awk your_file

测试如下:

> awk -f temp.awk temp
 2 ? 1 ? 2 ?
 1 ? 1 ? 1 ?
 0 0 1 ? 0 ?
 1 ? 1 1 2 2