使用 awk 检查一个变量中的一组特定列中的每一行与另一个变量中的三个特定列中的所有行的信息

使用 awk 检查一个变量中的一组特定列中的每一行与另一个变量中的三个特定列中的所有行的信息

我今天之前问过一个非常类似的问题,但是我后来意识到我需要增加命令的参数。我编辑了另一个参数的命令,但我对下一个参数的成功率较低,我不知道为什么。这是我正在尝试(但失败)解决的问题。

我需要使用 来检查一个变量中特定列集的每一行中的信息与另一个变量中两个特定列中的所有行的信息awk,并将行保留在第一个符合参数的变量中。

到目前为止,我曾尝试通过一个强大的awk命令来做到这一点,但都失败了。显然,我可以在外部循环中执行此操作,但它会非常慢,因为我有数百行或数千行要检查。我感谢解决这个问题的所有帮助,并且我一直在寻求改进 awk 的使用,所以如果您有解决方案,最好有一个解释,以便我可以学习和提高自己。

这是一个例子:

  • 假设我只想打印 中的行${ListToCheckFrom},如果第 2 列 >= 且第 3 列 <= 中任何一行的相应列${ListToCheckAgainst}。此外,来自 的第 1 列${ListToCheckFrom}必须与中的第 1 列相同${ListToCheckAgainst}

  • 输入示例:

ListToCheckFrom="r,2,3
C,22,24
C,12,13
C,51,59
C,15,20
C,13,18"
        
ListToCheckAgainst="C,25,50
C,22,30
C,12,18
C,15,17
C,1,12
C,60,200"

  • 预期输出:
C,22,24  
C,12,13
C,15,20
C,13,18
  • 我所尝试的基于我今天提出的一个更简单的问题的答案(感谢@AdminBee):
awk -F',' 'list=="constraints"{n++; low[n]=$2;high[n]=$3;c[n]=$1;next}
           {for (i=1;i<=n;i++) {if (($1==c[i])&&($2>=low[i]&&$2<=high[i])||($3>=low[i]&&$3<=high[i])) {print;next};}}' list=constraints <(echo "$ListToCheckAgainst") list=check <(echo "$ListToCheckFrom")

我正在使用Ubuntu。

答案1

建立在另一个答案你回到了上一个问题:

$ cat tst.sh
#!/usr/bin/env bash

ListToCheckFrom="r,2,3
C,22,24
C,12,13
C,51,59
C,15,20
C,13,18"

ListToCheckAgainst="C,25,50
C,22,30
C,12,18
C,15,17
C,1,12
C,60,200"

awk '
    BEGIN { FS="," }
    NR==FNR {
        vals[NR] = $0
        next
    }
    {
        for ( nr in vals ) {
            split(vals[nr],v)
            if ( (v[1] == $1) && ( (v[2] <= $2) && ($2 <= v[3]) ) ) {
                print
                next
            }
        }
    }
' <(printf '%s\n' "$ListToCheckAgainst") <(printf '%s\n' "$ListToCheckFrom")

$ ./tst.sh
C,22,24
C,12,13
C,15,20
C,13,18

关于您询问修改的脚本,这是对您上一个问题的回答:

awk -F',' 'list=="constr"{n++; low[n]=$2;high[n]=$3;next}
           {for (i=1;i<=n;i++) {if ($2>low[i]&&$2<high[i]) {print;next};}}' \
           list=constr <(echo "$ListToCheckAgainst") \
           list=chk <(echo "$ListToCheckFrom")

尝试增强它的第一步应该是使其更易于阅读,例如,如果您运行 awk 部分gawk -o-并将 shell 部分添加回其周围,您会得到以下结果:

awk -F',' '
    list == "constr" {
            n++
            low[n] = $2
            high[n] = $3
            next
    }
    
    {
            for (i = 1; i <= n; i++) {
                    if ($2 > low[i] && $2 < high[i]) {
                            print
                            next
                    }
            }
    }
' \
list=constr <(echo "$ListToCheckAgainst") \
list=chk <(echo "$ListToCheckFrom")

希望从那里很容易看出,要使其满足您的新要求,您所要做的就是将其更改为:

awk -F',' '
    list == "constr" {
            n++
            key[n] = $1
            low[n] = $2
            high[n] = $3
            next
    }
    
    {
            for (i = 1; i <= n; i++) {
                    if ( (key[i] == $1) && ($2 > low[i] && $2 < high[i]) ) {
                            print
                            next
                    }
            }
    }
' \
list=constr <(echo "$ListToCheckAgainst") \
list=chk <(echo "$ListToCheckFrom")

相关内容