如何使用if / else awk来评估文件并提取此信息?

时间:2015-12-16 12:44:59

标签: linux unix awk

我有一个这样的文件:

419 I     0.3529
420 S     0.3182
421 T     0.3740
422 Y     0.3872
423 I     0.3460
424 E     0.4409
425 S     0.3182
426 T     0.3740
427 Y     0.4141
428 I     0.3460
429 S     0.3131
430 Y     0.3838
431 T     0.3939
432 S     0.3101

我正在尝试制作一个Awk程序来评估大于或等于0.4的数字的第三列。如果为true,则在该字母中向上取4个字符,向下取4个字符(第二列)。如果有多个匹配,我想为每个匹配一个固定长度的字符串:

STYIESTYI
IESTYISYT

第一个是因为编号为424的线上有匹配;第二个是编号为427的行的(部分重叠)匹配。我将如何处理?

3 个答案:

答案 0 :(得分:4)

$ cat tst.awk
BEGIN {
    tgt = (tgt=="" ? 0.4 : tgt)
    cxt = (cxt=="" ?  4  : cxt)
    bef = (bef=="" ? cxt : bef)
    aft = (aft=="" ? cxt : aft)
}
$3 >= tgt { hits[++numHits] = NR }
{ chars[NR] = $2 }
END {
    for (hitNr=1; hitNr<=numHits; hitNr++) {
        for (lineNr=(hits[hitNr]-bef); lineNr<=(hits[hitNr]+aft); lineNr++) {
            printf "%s", (lineNr in chars ? chars[lineNr] : "")
        }
        print ""
    }
}

$ awk -f tst.awk file
STYIESTYI
IESTYISYT

请注意,如果第3个字段&gt; = 0.4的行比文件的开头和/或结尾的4行更接近,这将表现得很明智 - 请确保测试那些具有任何潜在答案的条件,因为它们是常见的对于这类问题的雨天案例,提供潜在解决方案的人往往忘记报道。

例如,尝试使用此输入文件的所有潜在解决方案,看看是否得到了您期望的输出:

$ cat file1
421 T     0.3740
422 Y     0.3872
423 I     0.3460
424 E     0.4409
425 S     0.3182
426 T     0.3740
427 Y     0.4141
428 I     0.3460
429 S     0.3131
430 Y     0.3838

$ awk -f tst.awk file1
TYIESTYI
IESTYISY

或者如果您丢失输出行或带有前导/尾随空格或其他不良字符或其他内容的行。

另请注意,您可以将目标值从0.4更改为其他值,并且可以通过设置命令行参数来更改要在匹配行之前和/或之后打印的数字上下文行,例如

在0.37之前和之后打印5行上下文:

$ awk -v tgt=0.37 -v cxt=5 -f tst.awk file
ISTYIEST
ISTYIESTY
ISTYIESTYIS
TYIESTYISYT
YIESTYISYTS
STYISYTS
TYISYTS

打印前一行和0.34后的两行:

$ awk -v tgt=0.34 -v bef=1 -v aft=2 -f tst.awk file
IST
STYI
TYIE
YIES
IEST
STYI
TYIS
YISY
SYTS
YTS

答案 1 :(得分:3)

myDict = {'a': # This is fine 'b'} # fine myDict = {'ä': # fine 'b'} # fine myTuple = ('a', # fine 'b') # fine myTuple = ('ä', # fine 'b') # fine myC = ('a', {'b': 'c', # fine 'd': 'e'}) # fine myC = ('ä', {'b': 'c', # fine 'd': 'e'}) # E128: continuation line under-indented[...] 救援!

awk

如果您的文件很大,滚动窗口可能是更好的解决方案。

更新:根据@Ed Morton的评论,脚本总是希望匹配后会有4条尾随线。如果不是这样,则需要添加特殊的END块来处理悬空线。

$ awk    '{a[NR]=$2; v[NR]=$3>0.4} 
   v[NR-4]{for(i=NR-8;i<=NR;i++) 
              printf "%s", a[i]; 
           print ""}' file

STYIESTYI
IESTYISYT

答案 2 :(得分:1)

这是怎么回事?跟踪最后四个字符并在匹配时将其打印出来。然后设置num以计算接下来的四个字符。请注意使用printf而不是print来避免自动换行。

// {if ($3 > 0.4) {printf "%s", v0 v1 v2 v3 ;
                   v0 = v1 = v2 = v3 = "";
                   num = 4} 
    if (num > 0) {
        printf "%s", $2;
        num = num -1;
    } else { v0 = v1; v1 = v2; v2 = v3; v3 = $2; }
    }