Bash 用数字匹配多个文件,并按数字排除其中一个文件
我有一系列文件,根据编号(File1.txt、File2.txt、File3.txt等)排序,我在脚本中运行循环作为awk代码的输入。我可以把这些模式匹配为Bash 用数字匹配多个文件,并按数字排除其中一个文件,bash,awk,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跳过该文件 我已经尝试了前面描述的复合模式匹
awk ... file[1-$i].txt >> output
但是,我希望排除该范围内的文件,例如
file$v.txt
目标
我在找像这样的东西
awk ... file[1-!$v-$i].txt >> output
在这里,我从1到$I匹配每个文件,用$v跳过该文件
我已经尝试了前面描述的复合模式匹配的各种输入,但是我无法让语法对我起作用 有人知道如何像这样进行复合模式匹配吗?多谢各位
样本输入 根据要求,以下是我的文件: 文件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
文件1.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
文件1.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
文件1.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
文件1.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代码
此代码执行以下操作:
33.679538 0.249302
在其他正确匹配的行中,但这行是我当前的测试,以查看它是否工作。现在,我有:
33.679538 0.378012
由于在awk代码中将file.4.dat添加到自身中,因此我无法在输入文件的第二个参数中排除它
问题摘要
我的awk代码正在读取我的所有输入文件,我需要排除其中一个文件以获得正确的输出
最后,我必须分别输入我的5个文件中的每一个,与上面awk代码中的其他4个文件相对照。将来,文件的数量将是可变的,因此我不能只在脚本中键入文件名。现在,如果我能解决这个问题,至少不超过10个文件,这将是一个很大的帮助。您可以在
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
shell的特性来包含除引用之外的所有文件。例如,我正在创建文件file1..10
来解释这一点
touch file{1..10}
exclude=3
使用内置的shopt
设置扩展shell选项
shopt -s extglob
list=(!(file"$exclude"))
现在使用declare-plist
打印数组,以查看仅排除引用文件的文件列表。现在使用awk
中的数组,如下所示。数组扩展“${list[@]}”
会导致上面生成的所有文件被排除
awk ... file"$exclude" "${list[@]}"
要跳过文件,只需将
ARGV[其在arg列表中的位置]
设置为null。e、 g:
$ ls
file1 file2 file3
$ grep . file*
file1:x
file2:y
file3:z
$ awk 'BEGIN{ARGV[2]=""} {print FILENAME, $0}' file*
file1 x
file3 z
或者,如果愿意,可以按名称而不是按参数列表中的顺序删除“坏”文件:
$ 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
如果有人不想使用或其系统中没有
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
的变量,我们可以提到需要忽略的名为的输入文件,一旦该输入文件用于解析,我将名为no\u parse
的标志设置为TRUE,在这种情况下,特定输入文件的no内容将被读取(因为next
用于跳过所有进一步的语句)使用流水线AWK。您必须提供最后一个文件作为参考(此处->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-- '
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
$
是的,我们可以用这种方式提到多个输入文件。请您在您的帖子中发布文件样本以及预期输出,然后让我们知道。
[1-$i]
不是您可能想到的数字范围——例如,[1-30]
匹配单个数字,0
、1
、2
和3
,因为它将1-3
和0
视为建立单个字符模式的两个元素。@RavinderSingh13好的,我会的。坦白说,在事实发生后进行过滤可能更有意义:shopt-s extglob
,然后files=();对于file+([[:digit:]]).txt中的文件;do fileNum=${file/[![:digit:][]/};((fileNum
,然后您可以awk。。。“${files[@]}”
来传递列表。@Inian,|
作为覆盖noclobber
的一种方法在bash中;请参阅手册的重定向部分。这对我很有效。非常感谢!为了将来读者根据我问题的主题进行搜索,是否可以指定匹配文件名的模式列表,同时从列表中排除一个模式?@Blaisem:是的,您可以构建一个文件数组并排除该文件。为了您愿意知道,我可以明天更新答案!:)@布莱森,请你也检查一下这个,如果有任何疑问请告诉我。
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
$