将多个文件与数字匹配,并按数字排除其中一个文件

时间:2019-03-05 16:42:45

标签: bash awk

我有一系列文件,根据编号(File1.txt,File2.txt,File3.txt等)排序,我在自己的脚本中运行一个循环作为awk代码的输入。我可以将这些匹配为

awk ... file[1-$i].txt >> output

但是我想排除该范围内的文件,例如

file$v.txt

目标

我正在寻找类似的东西

awk ... file[1-!$v-$i].txt >> output

我在其中匹配1- $ i中的每个文件,用$ v跳过该文件。


我已经按照here的描述尝试了来自复合模式匹配的各种输入,但是我无法获得适合我的语法。

有人知道怎么做这样的复合模式匹配吗?谢谢。


样本输入

根据要求,这是我的文件:

file.1.dat

29.078306 0.00676358
29.223592 0.00309192
30.297306 0.0174575
30.478883 0.132458
30.503705 0.118951
30.512891 0.0705088
31.945900 0.00408244
32.321011 0.00258023
32.894037 0.00407912
32.916263 0.00330154
34.594139 0.00874524
34.849178 0.0195172
34.884655 0.00547378
34.967403 0.00308369
35.325397 0.00818193

file.2.dat

25.970535 0.0979715
26.913976 0.00593039
29.078306 0.0984052
29.223592 0.00271504
30.236632 0.013818
30.478883 0.0347606
30.503705 0.102369
30.512891 0.0409633
31.714064 0.0242958
31.902306 0.0510168
32.715764 0.0146584
34.952965 0.00484555
35.190790 0.0114201
35.360372 0.0033089
35.575199 0.00282864
38.184618 0.00551692

file.3.dat

31.591771 0.0126916
32.059389 0.0605918
32.299959 0.122618
32.890418 0.0058495
32.962536 0.00492958
33.646214 0.0705359
33.679538 0.120592

file.4.dat

25.636267 0.00398174
27.848542 0.00485739
28.269278 0.0174401
29.418886 0.00409613
31.313212 0.203932
31.945900 0.00259743
32.256620 0.00325607
32.299959 0.0325366
33.461363 0.0798633
33.646214 0.0516498
33.679538 0.12871

file.5.dat

29.767600 0.00777448
32.299959 0.00777995
34.849178 0.0305844
34.884655 0.0126815
34.930799 0.0546924
34.952965 0.0711241

Awk代码

awk '
NR==FNR {
    a[$1]=$2
    next
}
($1 in a) {
    a[$1]+=$2
}
END {
    for(i in a)
        print i,a[i]
}' file.4.dat file.[1-5].dat >| test.out

此代码执行以下操作:

  1. 根据字段1($ 1)中的值,将file.4.dat匹配到file.1.dat,file.2.dat ... file.5.dat。
  2. 在$ 1中找到匹配项的地方,都会向file.4.dat中的匹配行$ 2添加$ 2。
  3. test.out打印file.4.dat,其中$ 2等于匹配的$ 1行中的$ 2。

this question中询问了我想做的一个简单示例,这是我从中获取awk代码的地方。

目标

我的目标是在输出中包含以下行:

33.679538 0.249302

在其他正确匹配的行中,但这是我当前的测试,以查看它是否有效。现在,我有:

33.679538 0.378012

由于在awk代码中将file.4.dat添加到自身中,因为我无法在输入文件的第二个参数中排除它。

问题摘要

我的awk代码正在读取我所有的输入文件,并且需要排除其中的一个文件才能获得正确的输出。

最终,我必须分别输入我的5个文件中的每个文件与上述awk代码中的其他4个文件。将来,文件的数量将是可变的,因此我不能只在脚本中键入文件名。现在,如果我至少可以解决少于10个文件的问题,那将是一个很大的帮助。

4 个答案:

答案 0 :(得分:2)

您只需在awk中执行此操作,方法是识别要用作参考的第一个文件,而忽略使用nextfile选项(需要GNU版本)进行后续处理的操作,该选项将跳过后续处理文件处理。按照这种逻辑,您应该放置参考文件,例如输入中的file.4.dat作为文件列表中的第一个参数。

awk '
BEGIN{ ignoreFile = ARGV[1] }
NR==FNR {
    a[$1]=$2
    next
}
FILENAME == ignoreFile { nextfile }
($1 in a) {
    a[$1]+=$2
}
END {
    for(i in a)
        print i,a[i]
}' file.4.dat file.[1-5].dat >| test.out

OP想知道他们是否可以构建可从Shell生成并使用的文件名模式列表。可以这样做,但是考虑到nextfile中相对简单的选项,这看起来可能很复杂。

据您了解,您有n个文件,其中一个将用作参考文件。我希望使用bash外壳程序的extglob功能包括除引用之外的所有文件。例如我正在创建文件file1..10来解释这一点

touch file{1..10}
exclude=3

扩展的shell选项是使用内置的shopt设置的

shopt -s extglob
list=(!(file"$exclude"))

现在使用declare -p list打印数组以查看仅排除参考文件的文件列表。现在,如下使用awk中的数组。数组扩展"${list[@]}"会导致排除上面生成的所有文件。

awk ... file"$exclude" "${list[@]}"

答案 1 :(得分:1)

要跳过文件,只需将ARGV[its position in the arg list]设置为null。例如:

$ ls
file1  file2  file3

$ grep . file*
file1:x
file2:y
file3:z

$ awk 'BEGIN{ARGV[2]=""} {print FILENAME, $0}' file*
file1 x
file3 z

或者,如果您愿意,可以按名称而不是arg列表中的顺序删除“坏”文件。

$ awk 'BEGIN{for (i in ARGV) if (ARGV[i]=="file2") ARGV[i]=""} {print FILENAME, $0}' file*
file1 x
file3 z

$ awk 'BEGIN{bad["file2"]; for (i in ARGV) if (ARGV[i] in bad) ARGV[i]=""} {print FILENAME, $0}' file*
file1 x
file3 z

$ awk '
    BEGIN {
        split("file2 file3",tmp); for (i in tmp) bad[tmp[i]]
        for (i in ARGV) if (ARGV[i] in bad) ARGV[i]=""
    }
    {print FILENAME, $0}
' file*
file1 x

答案 2 :(得分:0)

如果某人不想使用或系统中没有nextfile,则可以采取以下措施。

awk -v ignore="file.4.dat" '
FNR==1{
    no_parse=""
}
FNR==NR {
    a[$1]=$2
    next
}
FILENAME == ignore{
    no_parse=1
}
no_parse{
    next
}
($1 in a) {
    a[$1]+=$2
}
END {
    for(i in a)
        print i,a[i]
}' file.4.dat file.[1-5].dat >| test.out

创建了一个名为ignore的变量,我们可以在其中提及需要忽略的Input_file,一旦Input_file转向解析,我将一个名为no_parse的标志设置为TRUE,在这种情况下,将读取Input_file的内容(因为next用于跳过所有其他语句)

答案 3 :(得分:0)

使用流水线awks。您必须提供最后一个文件作为参考(此处-> 4)

awk ' $(NF+1)=FILENAME' file.[1-3].dat file.5.dat file.4.dat |  
   awk ' { a[$1]+=$2; $2=a[$1] } /file.4.dat/ && NF-- '

具有给定的文件

$ awk ' $(NF+1)=FILENAME' file.[1-3].dat file.5.dat file.4.dat |  
      awk ' { a[$1]+=$2; $2=a[$1] } /file.4.dat/ && NF-- '
25.636267 0.00398174
27.848542 0.00485739
28.269278 0.0174401
29.418886 0.00409613
31.313212 0.203932
31.945900 0.00667987
32.256620 0.00325607
32.299959 0.162935
33.461363 0.0798633
33.646214 0.122186
33.679538 0.249302

$