【问题标题】:Display only lines in which 1 column is equal to another, and a second column is in a range in AWK and Bash在 AWK 和 Bash 中仅显示一列等于另一列且第二列在某个范围内的行
【发布时间】:2014-05-24 07:56:49
【问题描述】:

我有两个文件。第一个文件如下所示:

1 174392 
1 230402
2 4933400
3 39322
4 42390021
5 80022392
6 3818110

等等

第二个文件如下所示:

chr1 23987 137011
chr1 220320 439292
chr2 220320 439292
chr2 2389328 3293292
chr3 392329 398191
chr4 421212 3292393

等等。

我想返回整行,前提是 FILE1 中的第一列 = FILE2 中的第一行,作为字符串匹配并且文件 2 中的第二列大于 FILE2 中的第 2 列但小于 FILE2 中的第 3 列.

所以在上面的例子中,行 1 230402
在 FILE1 和 chr1 220320 439292 在 FILE2 中将满足条件,因为 230402 在 220320 和 439292 之间,并且在我使字符串匹配后 1 将等于 chr1,因此将打印 FILE2 中的该行。

我写的代码是这样的:

#!/bin/bash

$F1="FILE1.txt"

read COL1 COL2
do
    grep -w "chr$COL1" FILE2.tsv \
    | awk -v C2=$COL2 '{if (C2>$1 && C2<$2); print $0}'
done < "$F1"

我已经尝试了很多变体。我不在乎代码是完全在 awk 中、完全在 bash 中还是混合在一起。

谁能帮忙?

谢谢!

【问题讨论】:

  • 我假设您的意思是 the first column in FILE1 = the first column in FILE2the 2nd column in FILE1 is greater than column 2 in FILE2?

标签: bash awk range match


【解决方案1】:

这是使用awk的一种方法:

awk '
NR==FNR {
    $1 = "chr" $1
    seq[$1,$2]++;
    next
}
{
    for(key in seq) {
        split(key, tmp, SUBSEP); 
        if(tmp[1] == $1 && $2 <= tmp[2] && tmp[2] <= $3 ) {
            print $0
        }
    }
}' file1 file2
chr1 220320 439292
  • 我们使用键作为第 1 列和第 2 列将第一个文件读入数组。我们将字符串“chr”添加到第 1 列,同时将其作为键以便稍后进行比较
  • 当我们处理文件 2 时,我们遍历我们的数组并拆分键。
  • 我们将第一段键与第 1 列进行比较,并检查第二段键是否在第二列和第三列的范围内。
  • 如果它满足我们的条件,我们打印该行。

【讨论】:

    【解决方案2】:
    awk 'BEGIN {i = 0}
         FNR == NR { chr[i] = "chr" $1; test[i++] = $2 }
         FNR < NR { for (c in chr) {
                    if ($1 == chr[c] && test[c] > $2 && test[c] < $3) { print }
                }
            }' FILE1.txt FILE2.tsv
    

    FNR 是当前文件中的行号,NR 是所有输入中的行号。所以第一个块处理第一个文件,将所有行收集到数组中。第二个块处理任何剩余的文件,搜索 chrN 值的数组以寻找匹配项,并将其他两个数字与第一个文件中的数字进行比较。

    【讨论】:

    • 我不确定这是否真的有问题,awk 在第一次使用时会自动将变量初始化为""。但是我添加了一个明确的0 初始化。
    • 显然你是对的,我尝试了换行的原始脚本,但失败了。但是更新的脚本有效。谢谢
    • 我认为空字符串将是哈希中的有效数组索引。
    • 我使用了后增量,所以它在 存储 column2 之后递增。
    • 啊,明白了——因为++是一个数字运算符,它返回转换为数字的原始值,而不是原始原始值。
    【解决方案3】:

    非常感谢!

    这些答案很有效,非常有帮助。

    我终于意识到我应该拥有:

    awk -v C2=$COL2 'if (C2>$1 && C2<$2); {print $0}'
    

    将支架放在不同的地方,我会没事的。

    无论如何,非常感谢!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-05-24
      • 2020-04-28
      • 2022-10-06
      • 1970-01-01
      • 2013-01-26
      • 1970-01-01
      • 1970-01-01
      • 2018-04-04
      相关资源
      最近更新 更多