是否可以从第一列包含与其他文件名称匹配的标识符的文件中提取某些行?
Is it possible to extract certain rows from a file where the first column contains an identifier that matches the names of other files?
我昨天在一个更大的问题中提出了这个问题。评论者建议将其拆分为自己的问题。
我有 x 个文件。前五个文件的内容如下所示。在第二行,i
是一个计数器,因此第一个文件的 i = 0
。 i
旁边是 time
,当 i
增加 1 时它总是增加 0.5。
但是,我只保留了第x个文件。因此,虽然我拥有的第一个文件 i = 0
,第二个文件 i = 100
,依此类推。
6 # This file is called "0.xyz" (<--the "6" is the same in all files)
i = 0, time = 0.000, k = 9000000000000
X -7.6415350292 6.0494971539 8.1919697993
Y -6.6418362233 5.9231018862 8.4056822626
Y -8.0518670684 6.3158684817 9.0061271154
X 26.8252967820 20.4661074967 17.8025744066
Y 26.4477411207 20.4071029058 16.9121571912
Y 26.4399648474 21.2950722068 18.1009273227
6 # This file is called "100.xyz"
i = 100, time = 50.000, k = 2500000000000
X -6.2423192714 -1.5704681396 -9.5648670474
Y -5.4925100813 -1.6522059045 -8.9030589772
Y -6.7765278574 -2.3616512405 -9.4776648590
X 4.1248924594 27.8487302083 -17.5400886312
Y 4.1238657681 26.9869907778 -17.9727402579
Y 5.0750649402 28.1292768156 -17.6848507559
6 # This file is called "200.xyz"
i = 200, time = 100.000, k = 3945000000000
X 19.0090162215 -5.9338939011 6.1931167954
Y 18.4748060757 -6.4905073540 5.6656446036
Y 19.2825591449 -6.4479943255 7.0179774953
X 11.0203415273 34.6029396705 2.7220660957
Y 11.1184002007 34.8398120338 1.8089008500
Y 10.3349649622 33.9509485292 2.5605794622
6 # This file is called "300.xyz"
i = 300, time = 150.000, k = 2341000000000
X -7.6415350292 6.0494971539 8.1919697993
Y -6.6418362233 5.9231018862 8.4056822626
Y -8.0518670684 6.3158684817 9.0061271154
X 26.8252967820 20.4661074967 17.8025744066
Y 26.4477411207 20.4071029058 16.9121571912
Y 26.4399648474 21.2950722068 18.1009273227
6 # This file is called "400.xyz"
i = 400, time = 200.000, k = 2500000000000
X -6.2423192714 -1.5704681396 -9.5648670474
Y -5.4925100813 -1.6522059045 -8.9030589772
Y -6.7765278574 -2.3616512405 -9.4776648590
X 4.1248924594 27.8487302083 -17.5400886312
Y 4.1238657681 26.9869907778 -17.9727402579
Y 5.0750649402 28.1292768156 -17.6848507559
我想做的是将这些文件(上方)与另一个文件(下方)的数据进行匹配。在下面的文件中,每一行根据i
(步骤)匹配上面的一个文件。然后我想将下面文件中匹配行的前三列打印到一个新文件中。
虽然我包含了文件名,但我更愿意使用 i
而不是文件名来进行匹配。
我知道如何通过简单的迭代来做到这一点。意思是,我可以计数并将下面文件的第 x 行打印到一个新文件中。但是,我想使用一种专门匹配 i
的更复杂的方法,因为这些文件非常长,并且可能缺少行,因此我最终会在上面的文件和我的文件之间不匹配想要这里
# Step Time Ax Ay Az Bx By Bz Cx Cy Cz Final
0 0.000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 3243.9033438318
1 0.500 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 3243.7307919244
2 1.000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 3243.5615395313
3 1.500 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 3243.3955453870
4 2.000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 3243.2327751298
...
100 50.000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 3243.9033438318
...
200 100.000 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 3243.7307919244
...
300 150.000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 3243.5615395313
301 150.500 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 3243.3955453870
...
400 200.000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 3243.2327751298
示例 我希望通过操作上面的文件来匹配问题顶部的示例文件集的结果:
0 0.000 14.8032123290
100 50.000 14.8032123290
200 100.000 14.8029498502
300 150.000 14.8026923814
400 200.000 14.8021922354
如果有人对如何处理此问题有任何提示,我将不胜感激。
您可以使用 awk
脚本来执行此操作,如下所示:
awk 'FNR == 1 {
if ([=10=] ~ /^i =/) {
dataFile = 0;
step[+0] = FILENAME;
}
else {dataFile = 1;}
}
dataFile == 1 && step[] {
print , , ;
}' *.xyz data.txt
(假设最终文件名为 data.txt
;根据需要更改)
FNR == 1
匹配每个文件的第一行,并且将从 xyz
文件中捕获步骤,或者设置一个标志表明我们已经到达数据文件。由于执行数学运算的请求, + 0
位将强制 awk
将第 3 个字段转换为数字( 即 ,删除尾随逗号) .
dataFile == 1 && step[$i]
匹配数据文件中在 xyz
文件中看到步长值的行。
注意:您必须在最终数据文件之前指定所有xyz
文件,以便在处理数据文件之前收集所有步骤。
抱歉,当我将上述解决方案放在一起时,我认为 # This file is called
行不是文件的一部分。修改后的脚本在这里:
awk '
FNR == 2 && FILENAME != ARGV[ARGC-1] {
step[+0] = FILENAME;
}
FILENAME == ARGV[ARGC-1] && step[] {
print , , ;
}' *.xyz data.txt
此版本使用 ARGV 和 ARGC 来确定是否正在处理“数据”文件。
- 如果不是数据文件和行号== 2,缓存“step”值
- 如果是数据文件,并且步骤在列表中,打印前3个字段
结果:
0 0.000 14.8032123290
100 50.000 14.8032123290
200 100.000 14.8029498502
300 150.000 14.8026923814
400 200.000 14.8021922354
假设:
- 匹配基于
i
(又名 step
)和 time
step / time / Ax
数据文件:
$ cat match.dat
# Step Time Ax Ay Az Bx By Bz Cx Cy Cz Final
0 0.000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 3243.9033438318
1 0.500 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 3243.7307919244
2 1.000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 3243.5615395313
3 1.500 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 3243.3955453870
4 2.000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 3243.2327751298
100 50.000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 3243.9033438318
200 100.000 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 3243.7307919244
300 150.000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 3243.5615395313
301 150.500 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 3243.3955453870
400 200.000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 3243.2327751298
一个awk
想法:
awk '
FNR==NR { if (FNR>1) # skip header line in 1st file
Ax[ OFS ]= # use step + OFS + time as index for Ax[] array
next
}
== "i" { gsub(/,/,"") # remove commas from line so we can use normal FS delimiter to pull ...
i= # field #3 (i) and ...
time= # field #6 (time)
if ( (i OFS time) in Ax) # if i + OFS + time is an index in Ax[] array ...
print i,time,Ax[i OFS time] # print our 3 values to stdout
}
' match.dat [0-9]*.xyz
这会生成:
0 0.000 14.8032123290
100 50.000 14.8032123290
200 100.000 14.8029498502
300 150.000 14.8026923814
400 200.000 14.8021922354
如果 OP 需要显示带有漂亮列的输出,一个想法是将结果通过管道传输到 column
,例如:
$ awk '...' match.dat [0-9]*.xyz | column -t
0 0.000 14.8032123290
100 50.000 14.8032123290
200 100.000 14.8029498502
300 150.000 14.8026923814
400 200.000 14.8021922354
注意:此代码匹配字符串的精确匹配; 不是根据数值匹配;所以 150 != 150.00
这可能适合您 (GNU sed):
sed -En '2~100s/^((\s*\S+){3}).*//p' file
打开扩展正则表达式并关闭隐式打印 -En
。
从第 2 行开始(header 之后的行)使用模数 100 到 select 所需的行,然后使用替换命令仅保留前三列。
如果必须使用初始文件进行匹配,则:
sed -En 's/^i =\s*(\S+),.*/s#^\(\s\*\(\s\*\S+\)\{2\}\)\.\*#\1#p/p' file1of5 |
sed -Enf - fileWithStep
这会生成一组 sed 命令,这些命令提取步骤值并将它们与具有步骤值的文件进行匹配,并仅检索前 3 列。
N.B。这五个文件可以在第一组 sed 命令后连接或单独命名,即用 file1 file2 file3 file4 file5
替换 file1of5
如果 它们包含唯一的步长值。
我昨天在一个更大的问题中提出了这个问题。评论者建议将其拆分为自己的问题。
我有 x 个文件。前五个文件的内容如下所示。在第二行,i
是一个计数器,因此第一个文件的 i = 0
。 i
旁边是 time
,当 i
增加 1 时它总是增加 0.5。
但是,我只保留了第x个文件。因此,虽然我拥有的第一个文件 i = 0
,第二个文件 i = 100
,依此类推。
6 # This file is called "0.xyz" (<--the "6" is the same in all files)
i = 0, time = 0.000, k = 9000000000000
X -7.6415350292 6.0494971539 8.1919697993
Y -6.6418362233 5.9231018862 8.4056822626
Y -8.0518670684 6.3158684817 9.0061271154
X 26.8252967820 20.4661074967 17.8025744066
Y 26.4477411207 20.4071029058 16.9121571912
Y 26.4399648474 21.2950722068 18.1009273227
6 # This file is called "100.xyz"
i = 100, time = 50.000, k = 2500000000000
X -6.2423192714 -1.5704681396 -9.5648670474
Y -5.4925100813 -1.6522059045 -8.9030589772
Y -6.7765278574 -2.3616512405 -9.4776648590
X 4.1248924594 27.8487302083 -17.5400886312
Y 4.1238657681 26.9869907778 -17.9727402579
Y 5.0750649402 28.1292768156 -17.6848507559
6 # This file is called "200.xyz"
i = 200, time = 100.000, k = 3945000000000
X 19.0090162215 -5.9338939011 6.1931167954
Y 18.4748060757 -6.4905073540 5.6656446036
Y 19.2825591449 -6.4479943255 7.0179774953
X 11.0203415273 34.6029396705 2.7220660957
Y 11.1184002007 34.8398120338 1.8089008500
Y 10.3349649622 33.9509485292 2.5605794622
6 # This file is called "300.xyz"
i = 300, time = 150.000, k = 2341000000000
X -7.6415350292 6.0494971539 8.1919697993
Y -6.6418362233 5.9231018862 8.4056822626
Y -8.0518670684 6.3158684817 9.0061271154
X 26.8252967820 20.4661074967 17.8025744066
Y 26.4477411207 20.4071029058 16.9121571912
Y 26.4399648474 21.2950722068 18.1009273227
6 # This file is called "400.xyz"
i = 400, time = 200.000, k = 2500000000000
X -6.2423192714 -1.5704681396 -9.5648670474
Y -5.4925100813 -1.6522059045 -8.9030589772
Y -6.7765278574 -2.3616512405 -9.4776648590
X 4.1248924594 27.8487302083 -17.5400886312
Y 4.1238657681 26.9869907778 -17.9727402579
Y 5.0750649402 28.1292768156 -17.6848507559
我想做的是将这些文件(上方)与另一个文件(下方)的数据进行匹配。在下面的文件中,每一行根据i
(步骤)匹配上面的一个文件。然后我想将下面文件中匹配行的前三列打印到一个新文件中。
虽然我包含了文件名,但我更愿意使用 i
而不是文件名来进行匹配。
我知道如何通过简单的迭代来做到这一点。意思是,我可以计数并将下面文件的第 x 行打印到一个新文件中。但是,我想使用一种专门匹配 i
的更复杂的方法,因为这些文件非常长,并且可能缺少行,因此我最终会在上面的文件和我的文件之间不匹配想要这里
# Step Time Ax Ay Az Bx By Bz Cx Cy Cz Final
0 0.000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 3243.9033438318
1 0.500 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 3243.7307919244
2 1.000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 3243.5615395313
3 1.500 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 3243.3955453870
4 2.000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 3243.2327751298
...
100 50.000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 3243.9033438318
...
200 100.000 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 3243.7307919244
...
300 150.000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 3243.5615395313
301 150.500 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 3243.3955453870
...
400 200.000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 3243.2327751298
示例 我希望通过操作上面的文件来匹配问题顶部的示例文件集的结果:
0 0.000 14.8032123290
100 50.000 14.8032123290
200 100.000 14.8029498502
300 150.000 14.8026923814
400 200.000 14.8021922354
如果有人对如何处理此问题有任何提示,我将不胜感激。
您可以使用 awk
脚本来执行此操作,如下所示:
awk 'FNR == 1 {
if ([=10=] ~ /^i =/) {
dataFile = 0;
step[+0] = FILENAME;
}
else {dataFile = 1;}
}
dataFile == 1 && step[] {
print , , ;
}' *.xyz data.txt
(假设最终文件名为 data.txt
;根据需要更改)
FNR == 1
匹配每个文件的第一行,并且将从 xyz
文件中捕获步骤,或者设置一个标志表明我们已经到达数据文件。由于执行数学运算的请求, + 0
位将强制 awk
将第 3 个字段转换为数字( 即 ,删除尾随逗号) .
dataFile == 1 && step[$i]
匹配数据文件中在 xyz
文件中看到步长值的行。
注意:您必须在最终数据文件之前指定所有xyz
文件,以便在处理数据文件之前收集所有步骤。
抱歉,当我将上述解决方案放在一起时,我认为 # This file is called
行不是文件的一部分。修改后的脚本在这里:
awk '
FNR == 2 && FILENAME != ARGV[ARGC-1] {
step[+0] = FILENAME;
}
FILENAME == ARGV[ARGC-1] && step[] {
print , , ;
}' *.xyz data.txt
此版本使用 ARGV 和 ARGC 来确定是否正在处理“数据”文件。
- 如果不是数据文件和行号== 2,缓存“step”值
- 如果是数据文件,并且步骤在列表中,打印前3个字段
结果:
0 0.000 14.8032123290
100 50.000 14.8032123290
200 100.000 14.8029498502
300 150.000 14.8026923814
400 200.000 14.8021922354
假设:
- 匹配基于
i
(又名step
)和time
step / time / Ax
数据文件:
$ cat match.dat
# Step Time Ax Ay Az Bx By Bz Cx Cy Cz Final
0 0.000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 3243.9033438318
1 0.500 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 3243.7307919244
2 1.000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 3243.5615395313
3 1.500 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 3243.3955453870
4 2.000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 3243.2327751298
100 50.000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 0.0000000000 0.0000000000 0.0000000000 14.8032123290 3243.9033438318
200 100.000 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 0.0000000000 0.0000000000 0.0000000000 14.8029498502 3243.7307919244
300 150.000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 0.0000000000 0.0000000000 0.0000000000 14.8026923814 3243.5615395313
301 150.500 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 0.0000000000 0.0000000000 0.0000000000 14.8024398604 3243.3955453870
400 200.000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 0.0000000000 0.0000000000 0.0000000000 14.8021922354 3243.2327751298
一个awk
想法:
awk '
FNR==NR { if (FNR>1) # skip header line in 1st file
Ax[ OFS ]= # use step + OFS + time as index for Ax[] array
next
}
== "i" { gsub(/,/,"") # remove commas from line so we can use normal FS delimiter to pull ...
i= # field #3 (i) and ...
time= # field #6 (time)
if ( (i OFS time) in Ax) # if i + OFS + time is an index in Ax[] array ...
print i,time,Ax[i OFS time] # print our 3 values to stdout
}
' match.dat [0-9]*.xyz
这会生成:
0 0.000 14.8032123290
100 50.000 14.8032123290
200 100.000 14.8029498502
300 150.000 14.8026923814
400 200.000 14.8021922354
如果 OP 需要显示带有漂亮列的输出,一个想法是将结果通过管道传输到 column
,例如:
$ awk '...' match.dat [0-9]*.xyz | column -t
0 0.000 14.8032123290
100 50.000 14.8032123290
200 100.000 14.8029498502
300 150.000 14.8026923814
400 200.000 14.8021922354
注意:此代码匹配字符串的精确匹配; 不是根据数值匹配;所以 150 != 150.00
这可能适合您 (GNU sed):
sed -En '2~100s/^((\s*\S+){3}).*//p' file
打开扩展正则表达式并关闭隐式打印 -En
。
从第 2 行开始(header 之后的行)使用模数 100 到 select 所需的行,然后使用替换命令仅保留前三列。
如果必须使用初始文件进行匹配,则:
sed -En 's/^i =\s*(\S+),.*/s#^\(\s\*\(\s\*\S+\)\{2\}\)\.\*#\1#p/p' file1of5 |
sed -Enf - fileWithStep
这会生成一组 sed 命令,这些命令提取步骤值并将它们与具有步骤值的文件进行匹配,并仅检索前 3 列。
N.B。这五个文件可以在第一组 sed 命令后连接或单独命名,即用 file1 file2 file3 file4 file5
替换 file1of5
如果 它们包含唯一的步长值。