【问题标题】:Avoid AWK printing an initial empty line避免 AWK 打印初始空行
【发布时间】:2014-12-14 11:43:52
【问题描述】:

我很确定这很简单,但我没有找到与此问题相关的问题。 我正在使用下一个代码在PosGen.bed 的第 5 列中打印给定基因的第一个起始位点和最终结束位点

awk 'BEGIN{ch=$1;ini=$2;fin=$3;gen=$5}{if(gen==$5){fin=$3}else{print ch"\t"ini"\t"fin"\t"gen;ch=$1;ini=$2;fin=$3;gen=$5}}}END{print ch"\t"ini"\t"fin"\t"gen}' PosGen.bed | head

我所做的是保留第一个站点>BEGINif 将验证下一行,甚至第一行是否具有相同的基因名称,如果是,则用新的结束位点刷新结束位点。 如果检测到其他基因名称,它将打印出所有实际信息并替换为新基因的信息。我的代码按预期工作,但我无法摆脱最初的那一行;这可以很容易地从输出文件中删除,但我渴望学习并最终掌握awk...

所以,问题是:我的代码打印了一个初始的空行,我还没有检测到原因,你知道为什么打印一个空行吗?

我虽然这是因为 {braquets} 放错了位置,但这似乎不是问题。 这是我得到的输出和输入的示例。

我们将不胜感激任何帮助! 谢谢!

输出文件(与我们的朋友空行)

chr1    3204563 3661429 Xkr4
chr1    4280927 4399268 Rp1
chr1    4481009 4486494 Sox17
chr1    4763279 4775758 Mrpl15

输入文件

chr1 3204563 3207049 - Xkr4
chr1 3206103 3206105 - Xkr4
chr1 3206106 3207049 - Xkr4
chr1 3411783 3411982 - Xkr4
chr1 3411783 3411982 - Xkr4
chr1 3660633 3661429 - Xkr4
chr1 3660633 3661579 - Xkr4
chr1 3661427 3661429 - Xkr4
chr1 4280927 4283093 - Rp1
chr1 4283062 4283064 - Rp1
chr1 4283065 4283093 - Rp1
chr1 4333588 4340172 - Rp1
chr1 4334681 4334683 - Rp1
chr1 4334684 4340172 - Rp1
chr1 4341991 4342162 - Rp1
chr1 4341991 4342162 - Rp1
chr1 4341991 4342162 - Rp1
chr1 4341991 4342162 - Rp1
chr1 4342283 4342906 - Rp1
chr1 4342283 4342918 - Rp1
chr1 4342283 4342918 - Rp1
chr1 4342283 4342918 - Rp1
chr1 4342904 4342906 - Rp1
chr1 4350281 4350395 - Rp1
chr1 4399251 4399268 - Rp1
chr1 4399251 4399322 - Rp1
chr1 4399266 4399268 - Rp1
chr1 4481009 4482749 - Sox17
chr1 4481797 4481799 - Sox17
chr1 4481800 4482749 - Sox17
chr1 4483181 4483487 - Sox17
chr1 4483181 4483547 - Sox17
chr1 4483485 4483487 - Sox17
chr1 4483853 4483944 - Sox17
chr1 4485217 4486023 - Sox17
chr1 4486372 4486494 - Sox17
chr1 4763279 4764597 - Mrpl15

【问题讨论】:

  • 空白非常便宜,在编写代码时投资一些总是明智的。简洁不是软件的理想属性——简洁才是。

标签: printing awk


【解决方案1】:

END 之前有一个额外的},这会使您的代码失败(给出错误),请将其删除。

BEGIN 部分不做任何事情,因为$1,$2 etc 在第一行运行之前不包含任何内容。

重写一些代码,使其更易于阅读。
由于gen 在首次运行时不包含任何内容,因此您的if 转到else 部分。
它做的第一件事就是打印inifingen。在第一次运行时,它不包含任何内容,给出空行(错误使用BEGIN

awk '
BEGIN {
    ch=$1
    ini=$2
    fin=$3
    gen=$5
}
{
    if (gen==$5) {
        fin=$3
    }
    else {
        print ch"\t"ini"\t"fin"\t"gen
        ch=$1
        ini=$2
        fin=$3
        gen=$5
    }
}
END {
    print ch"\t"ini"\t"fin"\t"gen
}
' file

PS 在此处发布时选择代码并单击{} 以概述代码。


所以要解决这个问题,请将BEGIN 更改为NR==1 使其在第一行运行,如下所示:

awk -v OFS='\t' '
NR==1 {
    ch=$1
    ini=$2
    fin=$3
    gen=$5
}
{
    if (gen==$5) {
        fin=$3
    }
    else {
        print ch, ini, fin, gen
        ch=$1
        ini=$2
        fin=$3
        gen=$5
    }
}
END {
    print ch, ini, fin, gen
}
' file
chr1    3204563 3661429 Xkr4
chr1    4280927 4399268 Rp1
chr1    4481009 4486494 Sox17
chr1    4763279 4764597 Mrpl15

【讨论】:

  • 非常感谢!确实我误解了BEGIN的用法
【解决方案2】:

正如@Jotne 指出的那样,您误解了BEGIN 的使用——它在打开第一个输入文件进行读取之前执行,因此$0$1 等没有填充在该部分中。试试这个:

$ cat tst.awk
BEGIN{ OFS="\t" }
{
    if ($5 == gen) {
        fin = $3
    }
    else {
        prtGen()
        ch  = $1
        ini = $2
        gen = $5
    }
}
END { prtGen() }

function prtGen() {
    if (ini != "") {
        print ch, ini, fin, gen
    }
}
$
$ awk -f tst.awk file
chr1    3204563 3661429 Xkr4
chr1    4280927 4399268 Rp1
chr1    4481009 4486494 Sox17
chr1    4763279 4764597 Mrpl15

请注意,如果输入文件为空,则上述内容不会产生任何输出,而这是您一直希望从文本处理脚本中获得的。

【讨论】:

    【解决方案3】:

    不是对起始空行问题的回答,但在这种情况下,如果输入文件是有序的,这种替代方法可能会很有趣:

    awk '$NF!=p{print x}{p=$NF}1' file | awk '{print $1,$2,$(NF-2),$NF}' RS=
    

    输出:

    chr1 3204563 3661429 Xkr4
    chr1 4280927 4399268 Rp1
    chr1 4481009 4486494 Sox17
    chr1 4763279 4764597 Mrpl15
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-01-03
      • 2012-07-09
      • 2018-02-17
      • 2013-01-09
      • 2021-02-27
      • 1970-01-01
      相关资源
      最近更新 更多