AWK在文件末尾

时间:2016-08-02 07:19:40

标签: awk

我有一个较旧的剧本,一直困扰我一段时间,其中有一个小错误,我还没有真正解决,但我认为这是关于时间的。该脚本基本上根据行的ID附加不同文件的列。例如......

test1.txt的:

a   3
b   2

的test2.txt:

a   5
b   9

......应该产生以下结果:

a   3   5
b   2   9

脚本本身如下:

#!/bin/bash
gawk 'BEGIN { OFS="\t" } 
    { vals[$1,ARGIND]=$2; keys[$1] } 
    END {
            for (key in keys) {
                printf "%s%s", key, OFS
                for (colNr=1; colNr<=ARGIND; colNr++) {
                    printf "%s%s", vals[key,colNr], (colNr<ARGIND?OFS:ORS)
            }
            } printf "\n"
    }' $1 $2

...称为$ script.sh test1.txt test2.txt。问题是我得到的结果不是完全我应该得到的结果:

a   3   5
b   2   9
NA  NA  NA

...即我在文件的最后加NA行。到目前为止,我只是手动删除了这一行,但不必这样做很好。我不知道这个奇怪的功能来自哪里,但是......有人有任何想法吗?如果重要的话,我在OSX上使用GAWK。

这里有一些实际的输入(这是我试图让问题变得简单而重要的!= P)

target_id       length  eff_length  est_counts  tpm
ENST00000574176 596     282         6           0.825408
ENST00000575242 103     718         105         5.19804
ENST00000573052 291     291         21          2.61356
ENST00000312051 223     192         2559        46.8843

我对target_idtpm列感兴趣,其他列不重要。我的完整剧本:

FILES=$(find . -name 'data.txt' | xargs)

# Get replicate names for column header
printf "%s" 'ENSTID'
for file in $FILES; do
    file2="${file/.results\/data.txt/}"
    file3="${file2/.\/*\//}"
    printf "\t%s" $file3
done
printf "\n"

gawk 'BEGIN { OFS="\t" } 
    { vals[$1,ARGIND]=$5; keys[$1] } 
    END {
            for (key in keys) {
                printf "%s%s", key, OFS
                for (colNr=1; colNr<=ARGIND; colNr++) {
                    printf "%s%s", vals[key,colNr], (colNr<ARGIND?OFS:ORS)
            }
            } printf "\n"
    }' $FILES

(即所有文件都名为data.txt,但位于不同名称的子文件夹中。)

2 个答案:

答案 0 :(得分:3)

更简单的惯用方法是

$ cat test1.txt
a   3
b   2
$ cat test2.txt 
a   5
b   9
$ awk -v OFS="\t" 'NR==FNR{rec[$1]=$0;next}$1 in rec{print rec[$1],$2}' test1.txt test2.txt
a   3   5
b   2   9

对于实际输入

$ cat test1.txt 
target_id       length  eff_length  est_counts  tpm
ENST00000574176 596     282         6           0.825408
ENST00000575242 103     718         105         5.19804
ENST00000573052 291     291         21          2.61356
ENST00000312051 223     192         2559        46.8843
$ cat test2.txt 
target_id       length  eff_length  est_counts  tpm
ENST00000574176 996     122         6           0.3634
ENST00000575242 213     618         105         7.277
ENST00000573052 329     291         89          2.0356
ENST00000312051 21      00          45          0.123
$ awk 'NR==FNR{rec1[$1]=$1;rec2[$1]=$5;next}$1 in rec1{printf "%-20s %-15s %-15s\n", rec1[$1],rec2[$1],$5}' test1.txt test2.txt
target_id            tpm             tpm            
ENST00000574176      0.825408        0.3634         
ENST00000575242      5.19804         7.277          
ENST00000573052      2.61356         2.0356         
ENST00000312051      46.8843         0.123 

注意:

  1. -v OFS="\t"用于输出中的制表符分隔字段,传递文件的顺序很重要(对第一个解决方案很重要)。
  2. 硬编码换行符,如

    printf "%-20s %-15s %-15s\n", rec1[$1],rec2[$1],$5
    

    不是一个好主意,因为它会使脚本不那么便携。您可以用

    替换它
    printf "%-20s %-15s %-15s", rec1[$1],rec2[$1],$5;print # same effect
    
  3. 编辑:对于两个以上的文件

    $ shopt -s globstar
    $ awk 'NR==FNR{rec1[$1]=$1" "$5;next}{if($1 in rec1){rec1[$1]=rec1[$1]" "$5}else{rec1[$1]=$1" "$5}}END{for(i in rec1){if(i != "target_id"){print rec1[i];}}}' **/test*.txt
    ENST00000312051 46.8843 46.8843 0.123 46.8843 0.123
    ENST00000573052 2.61356 2.61356 2.0356 2.61356 2.0356
    ENST00000575242 5.19804 5.19804 7.277 5.19804 7.277
    ENST00000574176 0.825408 0.825408 0.3634 0.825408 0.3634
    ENST77777777777 01245
    ENST66666666666 7.277 7.277
    $ shopt -u globstar
    

答案 1 :(得分:2)

据我所知,你在输出结尾处获得一个空行的唯一原因(这是我在OS X上使用gawk得到的)是你有一个{{1}在脚本的末尾,即使您刚刚打印printf "\n",也会添加换行符。

由于您的ORS脚本本质上是一个bash脚本,因此我会从中制作一个正确的awk脚本。这样可以额外避免在shell脚本中引用awk$1的错误问题(会破坏外来文件名)。如果它理解Awk:

,这也可以在您喜欢的文本编辑器中为您提供正确的语法高亮显示
$2

使用更复杂的#!/usr/bin/gawk -f BEGIN { OFS = "\t" } { vals[$1,ARGIND] = $2; keys[$1] = 1; } END { for (key in keys) { printf("%s%s", key, OFS); for (colNr = 1; colNr <= ARGIND; colNr++) { printf("%s%s", vals[key,colNr], (colNr < ARGIND ? OFS : ORS)); } } } 编辑脚本也可以做到这一点。

相关问题