Bash 使用awk命令比较单独行上的值?

Bash 使用awk命令比较单独行上的值?,bash,for-loop,awk,Bash,For Loop,Awk,我正在尝试构建一个bash脚本,该脚本使用awk命令逐行遍历一个以制表符分隔的排序文件,并确定是否: 该行的字段1(分子)与下一行相同 行的字段5(绞线)是字符串“减号”,并且 下一行的字段5是字符串“plus” 如果这是真的,我想将第1行的字段1和3中的值以及下一行的字段4中的值添加到文件中。对于上下文,排序后,输入文件如下所示: molecule gene start end strand ERR2661861.3269 JN051170.1 113

我正在尝试构建一个bash脚本,该脚本使用awk命令逐行遍历一个以制表符分隔的排序文件,并确定是否:

  • 该行的字段1(分子)与下一行相同
  • 行的字段5(绞线)是字符串“减号”,并且
  • 下一行的字段5是字符串“plus”
  • 如果这是真的,我想将第1行的字段1和3中的值以及下一行的字段4中的值添加到文件中。对于上下文,排序后,输入文件如下所示:

    molecule        gene    start   end     strand
    ERR2661861.3269 JN051170.1      11330   10778   minus
    ERR2661861.3269 JN051170.1      11904   11348   minus
    ERR2661861.3269 JN051170.1      12418   11916   minus
    ERR2661861.3269 JN051170.1      13000   12469   minus
    ERR2661861.3269 JN051170.1      13382   13932   plus
    ERR2661861.3269 JN051170.1      13977   14480   plus
    ERR2661861.3269 JN051170.1      14491   15054   plus
    ERR2661861.3269 JN051170.1      15068   15624   plus
    ERR2661861.3269 JN051170.1      15635   16181   plus
    
    因此,在本例中,在比较第4行和第5行时,脚本应该找到true语句,并将以下行附加到文件中:

    ERR2661861.3269      13000   13382
    
    到目前为止,我的剧本是:

    # test input file
    file=Eg2.1.txt.out
    
    #sort the file by 'molecule' field, then 'start' field
    sort -k1,1 -k3n $file > sorted_file
    
    # create output file and add 'molecule' 'start' and 'end' headers
    echo molecule$'\t'start$'\t'end >> Test_file.txt
    
    # for each line of the input file, do this
    for i in $sorted_file
    do
        # check to see if field 1 on current line is the same as field 1 on next line AND if field 5 on current line is "minus" AND if field 5 on next line is "plus"
        if  [awk '{if(NR==i) print $1}' == awk '{if(NR==i+1) print $1}'] && [awk '{if(NR==i) print $5}' == "minus"] && [awk '{if(NR==i+1) print $5}' == "plus"];
        
        # if this is true, then get the 1st and 3rd fields from current line and 4th field from next line and add this to the output file
        then
            mol=awk '{if(NR==i) print $1}'
            start=awk '{if(NR==i) print $3}'
            end=awk '{if(NR==i+1) print $4}'
            new_line=$mol$'\t'$start$'\t'$end   
            echo new_line >> Test_file.txt
        fi
    done
    
    bash脚本的第一部分按照我的要求工作,但是for循环似乎在排序文件中找不到任何点击。是否有人有任何见解或建议来解释为什么这可能无法达到预期效果

    非常感谢

    解释为什么您的代码不工作 有关问题的更好解决方案,请参阅

    bash中的字符串比较需要
    [
    ]
    Bash解释您的命令

    [awk '{if(NR==i) print $1}' == awk '{if(NR==i+1) print $1}']
    
    。。。由于命令
    [awk
    带有参数
    {if(NR..
    =
    awk
    {if(NR..]
    。在您的平均系统中,没有名为
    [awk
    的命令,因此这应该会失败并显示一条错误消息。在
    [
    ]之前添加一个空格

    awk
    未执行
    [awk=awk]
    只比较文字字符串
    awk
    。要执行命令并比较其输出,请使用
    [“$(awk)”=“$(awk)”]

    awk
    缺少输入文件
    awk'{…}'
    尝试从stdin(在您的情况下是用户)读取输入。由于要读取该文件,请将其添加为参数:
    awk'{…}'排序的\u文件

    awk'..NR==i…“
    没有引用bash的
    中的
    i
    
    awk
    不知道您的bash变量。当您在
    awk
    脚本中写入
    i
    时,
    i
    将始终具有默认值
    0
    。要将变量从
    bash
    传递到
    awk
    请使用
    awk-v i=“$i”…
    。此外,您似乎假设
    for i in
    将迭代文件的行号。现在,情况并非如此,请参见下一段

    $sorted_file中的i的
    未迭代文件
    sorted_file
    您调用了您的文件
    sorted\u file
    。但是当您编写
    $sorted\u file
    时,您引用了一个以前未声明的变量。未声明的变量扩展为空字符串,因此您不会迭代任何内容。
    您可能想为$(cat sorted_file)中的i编写
    ,但这将迭代文件内容,而不是行号。此外,根据文件内容,未加引号的
    $()
    可能会导致无法格式化的问题。要迭代行号,请使用
    for i in$(seq$(wc-l sorted_file))

    解释您的代码不起作用的原因 有关问题的更好解决方案,请参阅

    bash中的字符串比较需要
    [
    ]
    Bash解释您的命令

    [awk '{if(NR==i) print $1}' == awk '{if(NR==i+1) print $1}']
    
    …作为参数为
    {if(NR.
    =
    awk
    {if(NR.]
    的命令
    [awk
    。在您的平均系统中,没有名为
    [awk
    的命令,因此这应该会失败并显示一条错误消息。在
    [
    之后和
    之前添加一个空格

    awk
    未执行
    [awk=awk]
    只比较文字字符串
    awk
    。要执行命令并比较其输出,请使用
    [“$(awk)”=“$(awk)”]

    awk
    缺少输入文件
    awk'{…}'
    尝试从stdin(在您的情况下是用户)读取输入。由于要读取该文件,请将其添加为参数:
    awk'{…}'排序的\u文件

    awk'..NR==i…“
    没有引用bash的
    中的
    i
    
    awk
    不知道您的bash变量。当您在
    awk
    脚本中写入
    i
    时,
    i
    将始终具有默认值
    0
    。要将变量从
    bash
    传递到
    awk
    请使用
    awk-v i=“$i”…
    。此外,您似乎假设
    for i in
    将迭代文件的行号。现在,情况并非如此,请参见下一段

    $sorted_file中的i的
    未迭代文件
    sorted_file
    您调用了您的文件
    sorted\u file
    。但是当您编写
    $sorted\u file
    时,您引用了一个以前未声明的变量。未声明的变量扩展为空字符串,因此您不会迭代任何内容。

    您可能想为$(cat sorted_file)中的i编写
    ,但这将迭代文件内容,而不是行号。此外,根据文件内容,未加引号的
    $()
    可能会导致无法格式化的问题。要迭代行号,请使用
    for i in$(seq$(wc-l sorted_file))

    这将完成最后一步,假设数据在键中排序,“减”在“加”之前


    请注意,
    awk
    有一个隐式循环,无需强制它在外部进行迭代。

    这将完成最后一步,假设数据在键中排序,“减”在“加”之前


    请注意,
    awk
    有一个隐式循环,无需强制它在外部进行迭代。

    当使用awk或任何其他程序比较流中的相邻行时,最好的做法是存储该行的相关数据,然后在两行都被读取后立即进行比较,如
    molecule = $1
    strand = $5
    if (molecule==last_molecule)
      if (last_strand=="minus")
        if (strand=="plus")
          print $1,end,$4
    last_molecule = molecule
    last_strand = strand
    end = $3
    
    perl -lanE 'if ($l0==$F[0] && $l4 eq "minus" && $F[4] eq "plus") {say join("\t", @F[0..2])}
                $l0=$F[0]; $l4=$F[4];' sorted_file
    
    awk '($1==l1 && l5=="minus" && $5=="plus"){print $1 "\t" $2 "\t" $3}
         {l1=$1;l5=$5}' sorted_file 
    
    ruby -lane 'BEGIN{l0=l4=""}
    puts $F[0..2].join("\t") if (l0==$F[0] && l4=="minus" && $F[4]=="plus")
    l0=$F[0]; l4=$F[4]
    ' sorted_file
    
    ERR2661861.3269 JN051170.1  13382