【问题标题】:AWK negative regular expression with variable带变量的 AWK 负正则表达式
【发布时间】:2020-11-14 09:22:25
【问题描述】:

我在 bash 脚本中使用 awk 来比较两个文件以获取不匹配的行。 我需要将第二个文件的所有三个字段(作为一个模式?)与第一个文件的所有行进行比较:

第一个文件:

chr1    9997    10330   HumanGM18558_peak_1     150     .       10.78887        18.86368        15.08777        100
chr1    628885  635117  HumanGM18558_peak_2     2509    .       83.77238        255.95094       250.99944       5270
chr1    15966215        15966638        HumanGM18558_peak_3    81      .       7.61567 11.78841        8.17169 200

第二个文件:

chr1 628885 635117
chr1 1250086 1250413
chr1 16613629 16613934
chr1 16644496 16644800
chr1 16895871 16896489
chr1 16905126 16905616

目前的思路是在一个数组中加载一个文件,使用AWK的负正则表达式进行比较。

readarray a < file2.txt
for i in "${a[@]}"; do
awk -v var="$i" '!/var/' file1.narrowPeak | cat > output.narrowPeak
done

问题是'!/var/' 没有使用变量。

【问题讨论】:

  • 请将该示例输入的所需输出(无描述)添加到您的问题(无评论)。
  • 仔细查看stackoverflow.com/questions/19075671/…,只有一条关于如何将变量用作正则表达式的评论,而不是该问题中负正则表达式的提示。$0 !~ var 是您正在寻找的依据问题标题,但是使用 awk 而不是 bash+awk 有更好的解决方案
  • 为什么不grep -v "$i"
  • 另外使用 shell 循环来处理文本是个坏主意。检查unix.stackexchange.com/questions/169716/…
  • 管道到cat 是我的新UUOC

标签: regex bash shell awk


【解决方案1】:

单独使用awk

$ awk 'NR==FNR{a[$1,$2,$3]; next} !(($1,$2,$3) in a)' file2 file1
chr1    9997    10330   HumanGM18558_peak_1     150     .       10.78887        18.86368        15.08777        100
chr1    15966215        15966638        HumanGM18558_peak_3    81      .       7.61567 11.78841        8.17169 200
  • NR==FNR 这仅适用于第一个文件,在此示例中为 file2
  • a[$1,$2,$3]根据前三个字段创建键,如果两个文件之间的间距完全相同,您可以简单地使用$0而不是$1,$2,$3
  • next 跳过剩余的命令并处理下一行输入
  • ($1,$2,$3) in a 检查file1 的前三个字段是否作为数组a 中的键存在。然后反转条件。

这是另一种写法(感谢 Ed Morton)

awk '{key=$1 FS $2 FS $3} NR==FNR{a[key]; next} !(key in a)' file2 file1

【讨论】:

    【解决方案2】:

    当模式存储在变量中时,必须使用匹配运算符:

    awk -v var="something" '
      $0 !~ var {print "this line does not match the pattern"}
    '
    

    有了这个问题,正则表达式匹配看起来有点尴尬。我会选择 Sundeep 的解决方案,但如果你真的想要正则表达式:

    awk '
      NR == FNR {
        # construct and store the regex
        patt["^" $1 "[[:blank:]]+" $2 "[[:blank:]]+" $3 + "[[:blank:]]"] = 1
        next
      }
      {
        for (p in patt)
          if ($0 ~ p)
            next
        print
      }
    ' second first
    

    【讨论】:

    • 如果您将pattp 替换为regexpsr,第二个脚本会更清晰,因为文本匹配中没有patterns,只有regexps 或@987654329 @。在填充数组的每个正则表达式的末尾都需要一个"$",以避免错误匹配。你不需要= 1
    • 对,但不是$,我想要一个空格(或一些分隔符)。
    • 我喜欢有一个任务,个人风格。同意不同意“模式”的使用。
    • 很公平。对我来说,看到pattern 的代码就像申请在动物园打扫笼子的工作,他们只会告诉你,你会和animals 在笼子里。就我个人而言,我想知道是兔子还是老虎,但我想是 YMMV :-)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-15
    • 2020-04-06
    • 1970-01-01
    相关资源
    最近更新 更多