Awk 按强制顺序按特定元素筛选文件

Awk 按强制顺序按特定元素筛选文件,awk,filter,range,Awk,Filter,Range,我试图通过索引列过滤文件,并确保留下一些数字。在原始文件file1.txt中,索引列通常具有0到10之间的任意数字 示例文件中的破折号将每个块彼此分开: file1.txt index age_1 age_2 0 44 34 1 10 12 1 34 44 2 1 -3 3 4 -10.3 3 3.390 4 4 43 3 -- 1 -90

我试图通过索引列过滤文件,并确保留下一些数字。在原始文件file1.txt中,索引列通常具有0到10之间的任意数字

示例文件中的破折号将每个块彼此分开:

file1.txt
index age_1  age_2
    0  44      34
    1  10      12
    1  34      44
    2   1      -3
    3   4     -10.3
    3   3.390   4
    4  43       3
    --
    1 -90.3     2
    2  32       3
    3  43     -20
    4   2       2
    --
    0  34      34
    2  21      12
    4  -0.9    12
    --
    4  -2.19   34
    4   4       4
    5   5       -1
    6   4      12
    --
    3  -12      3
我试图分别过滤破折号之间的每个块,并将索引列中的范围从1到4的块与每个元素1、2、3、4至少保持一次。 因此,预期输出如下所示:

index age_1  age_2
    1  10      12
    1  34      44
    2   1      -3
    3   4     -10.3
    3   3.390   4
    4  43       3
    --
    1 -90.3     2
    2  32       3
    3  43     -20
    4   2       2
我当前的试用版只能检查索引列中的范围,但我无法指定强制筛选:

cat file1.txt | awk -v OFS="\t" '$1=$1' | tail -n +2 | awk '$1>=1 && $1<=4'
1   10  12
1   34  44
2   1   -3
3   4   -10.3
3   3.390   4
4   43  3
1   -90.3   2
2   32  3
3   43  -20
4   2   2
2   21  12
4   -0.9    12
4   -2.19   34
4   4   4
3   -12 3
我丢失了块,所有的输出在没有特定过滤的情况下都是混合的。它可以打印1到4之间的任何数字


如何通过将每个区块分开来对特定列中的数字进行严格筛选?

要确定区块的第一列是否包含所选范围内的所有数字,您可以在处理区块时索引数组中的第一列元素,并将其长度与末尾的范围大小进行比较,如中所述下面是脚本

$ cat tst.awk
NR == 1 {
  print
  next
}
$1 == "--" {
  if (length(arr) == 4) {
    printf "%s%s", sep, buf
  }
  sep = ($0 ORS)
  buf = ""
  delete arr
}
$1 >= 1 && $1 <= 4 {
  buf = (buf $0 ORS)
  arr[$1]
}
END {
  if (length(arr) == 4) {
    printf "%s%s", sep, buf
  }
}

要确定块的第一列是否包含选定范围内的所有数字,可以在处理块的同时对数组中的第一列元素进行索引,并将其长度与末尾的范围大小进行比较,如下面的脚本所示

$ cat tst.awk
NR == 1 {
  print
  next
}
$1 == "--" {
  if (length(arr) == 4) {
    printf "%s%s", sep, buf
  }
  sep = ($0 ORS)
  buf = ""
  delete arr
}
$1 >= 1 && $1 <= 4 {
  buf = (buf $0 ORS)
  arr[$1]
}
END {
  if (length(arr) == 4) {
    printf "%s%s", sep, buf
  }
}

这只是编写解决方案的一种稍微不同的方法。我们提出了同样的方法,但他先发布了。我对他的进行了升级,并打算删除我的,但最终决定将其留在这里,作为实现相同方法的替代方法。主要区别在于我使用了一个函数来包含打印代码,以防有人感兴趣,但他是第一个,所以他应该获得投票

$ cat tst.awk
NR==1 { print; next }
($1 >= 1) && ($1 <= 4) {
    rec = rec $0 ORS
    hits[$1]
}
$1 == "--" {
    rec = rec $0 ORS
    prt()
}
END { prt() }

function prt() {
    if ( length(hits) == 4 ) {
        printf "%s", rec
    }
    rec = ""
    delete hits
}

$ awk -f tst.awk file
index age_1  age_2
    1  10      12
    1  34      44
    2   1      -3
    3   4     -10.3
    3   3.390   4
    4  43       3
    --
    1 -90.3     2
    2  32       3
    3  43     -20
    4   2       2
    --

这只是编写解决方案的一种稍微不同的方法。我们提出了同样的方法,但他先发布了。我对他的进行了升级,并打算删除我的,但最终决定将其留在这里,作为实现相同方法的替代方法。主要区别在于我使用了一个函数来包含打印代码,以防有人感兴趣,但他是第一个,所以他应该获得投票

$ cat tst.awk
NR==1 { print; next }
($1 >= 1) && ($1 <= 4) {
    rec = rec $0 ORS
    hits[$1]
}
$1 == "--" {
    rec = rec $0 ORS
    prt()
}
END { prt() }

function prt() {
    if ( length(hits) == 4 ) {
        printf "%s", rec
    }
    rec = ""
    delete hits
}

$ awk -f tst.awk file
index age_1  age_2
    1  10      12
    1  34      44
    2   1      -3
    3   4     -10.3
    3   3.390   4
    4  43       3
    --
    1 -90.3     2
    2  32       3
    3  43     -20
    4   2       2
    --

我想说的是,如果你能为每一张唱片拆分1234,arr并删除arr[$1],不是更好吗?那你就这么做吧!lengtharr并打印块,但随后删除了。我经过了几次迭代,其中一次我认为OP想要列表中的1美元而不是范围中的1美元,当时我正在使用拆分。我想说,如果你拆分1 2 3 4,arr并删除每条记录的arr[$1],不是更好吗?那你就这么做吧!lengtharr并打印块,但随后删除了。我经过了几次迭代,其中一次我认为OP想要列表中的1美元而不是范围中的1美元,那是我使用拆分的时候。谢谢你的回答。这个解决方案确实有一个错误:致命:尝试使用标量'arr'作为数组,那么,arr在这里指的是什么?谢谢你的回答。这个解决方案确实有一个错误:致命:尝试使用标量'arr'作为数组。那么,arr在这里指的是什么?