在文件中查找模式并将每第 n 次出现打印到另一个文件
Find pattern in file and print every xth occurrence to another file
我有一个非常大的文件,类似于下面的代码片段。该片段显示了三个数据块。它们来自三个不同的时间步长 (i)。
6 # <--This is the same for all data blocks (i.e., always 6 rows of data)
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
i = 1, time = 0.500, 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
i = 2, time = 1.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
- 我想每第 100 个数据块打印到一个新文件。
@potong 在下面 link 的回答看起来很有希望(如果我理解,其他答案取决于数据块之间的空白行,而我没有)。我设法用它来将每个不同的块打印到它自己的文件中。但是我最终得到了太多文件。如果有人知道如何调整 potong 的方法以便它只适用于每个 xth 块,我将非常感谢您的提示。
Find specific pattern and print complete text block using awk or sed
如果我这样做,我需要对第二个(对应的)文件进行类似的修改,如下所示:
0 0.000 13.6600000000 0.0000000000 0.0000000000 0.0000000000 13.6600000000 0.0000000000 0.0000000000 0.0000000000 13.6600000000 2548
这是第一行。前两列对应上面第一个数据块中的i = 0, time = 0.000
。 我需要将这一行和每第 x 行打印到一个新文件,这样我就有两个包含来自相同时间步的数据的文件。
我可以想办法将每 xth 行放入一个新文件中,但如果有办法确保前两列与上面 (1) 中的 i = 0, time = 0.000
匹配,那将是很好的了解 (这样,如果一行打印失败或文件中重复了一个时间步长,我就不会以不匹配结束。
我添加了一个“Awk”标签,因为这似乎是 Awk 可以做的事情,但我没有使用 Awk 的经验。
注意: 仅解决 OP 的第一个要求,即每第 100 个块打印到 separate/new 文件 ...
假设:
- 每个块由 8 行组成(独立
6
、i = ...
行和 6 条数据行)
- 将每个感兴趣的 8 行块转储到单独的输出文件
- 输出文件名格式:
block.<block_count>.dat
(OP 可以根据要求更改)
示例数据:
$ cat block.dat
6 # block #1
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 # block #2
i = 1, time = 0.500, 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 # block #3
i = 2, time = 1.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 # block #4
i = 2, time = 1.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
一个 awk
想法打印出每个 xth
区块
x=2 # set to 100 per OP's requirement
awk -v x="${x}" '
== "6" { count++ }
!(count % x) { print > "block." count ".dat"}
' block.dat
这会生成:
for f in block.*.dat
do
echo "########### $f"
cat $f
done
########### block.2.dat
6 # block #2
i = 1, time = 0.500, 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
########### block.4.dat
6 # block #4
i = 2, time = 1.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
这可能适合您 (GNU sed):
sed -nE '/^6/{:a;N;s/[^\n]*/&/8;Ta;x;s/^/x/;/x{100}/{z;x;p;x};x}' file
关闭隐式打印并启用扩展正则表达式 -nE
。
从以 6
开头的行开始,收集 8 行然后交换到保持 space,递增计数器,测试计数器是否出现所需的次数(在本例中为 100 ) 如果是,则将计数器归零,换回模式 space,打印它,然后 return 到保留 space。在所有情况下 return 到模式 space.
N.B。可以更改记录中的行数(在本例中为 8)以及输出记录数(在本例中为 100)。
我有一个非常大的文件,类似于下面的代码片段。该片段显示了三个数据块。它们来自三个不同的时间步长 (i)。
6 # <--This is the same for all data blocks (i.e., always 6 rows of data)
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
i = 1, time = 0.500, 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
i = 2, time = 1.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
- 我想每第 100 个数据块打印到一个新文件。
@potong 在下面 link 的回答看起来很有希望(如果我理解,其他答案取决于数据块之间的空白行,而我没有)。我设法用它来将每个不同的块打印到它自己的文件中。但是我最终得到了太多文件。如果有人知道如何调整 potong 的方法以便它只适用于每个 xth 块,我将非常感谢您的提示。
Find specific pattern and print complete text block using awk or sed
如果我这样做,我需要对第二个(对应的)文件进行类似的修改,如下所示:
0 0.000 13.6600000000 0.0000000000 0.0000000000 0.0000000000 13.6600000000 0.0000000000 0.0000000000 0.0000000000 13.6600000000 2548
这是第一行。前两列对应上面第一个数据块中的i = 0, time = 0.000
。 我需要将这一行和每第 x 行打印到一个新文件,这样我就有两个包含来自相同时间步的数据的文件。
我可以想办法将每 xth 行放入一个新文件中,但如果有办法确保前两列与上面 (1) 中的 i = 0, time = 0.000
匹配,那将是很好的了解 (这样,如果一行打印失败或文件中重复了一个时间步长,我就不会以不匹配结束。
我添加了一个“Awk”标签,因为这似乎是 Awk 可以做的事情,但我没有使用 Awk 的经验。
注意: 仅解决 OP 的第一个要求,即每第 100 个块打印到 separate/new 文件 ...
假设:
- 每个块由 8 行组成(独立
6
、i = ...
行和 6 条数据行) - 将每个感兴趣的 8 行块转储到单独的输出文件
- 输出文件名格式:
block.<block_count>.dat
(OP 可以根据要求更改)
示例数据:
$ cat block.dat
6 # block #1
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 # block #2
i = 1, time = 0.500, 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 # block #3
i = 2, time = 1.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 # block #4
i = 2, time = 1.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
一个 awk
想法打印出每个 xth
区块
x=2 # set to 100 per OP's requirement
awk -v x="${x}" '
== "6" { count++ }
!(count % x) { print > "block." count ".dat"}
' block.dat
这会生成:
for f in block.*.dat
do
echo "########### $f"
cat $f
done
########### block.2.dat
6 # block #2
i = 1, time = 0.500, 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
########### block.4.dat
6 # block #4
i = 2, time = 1.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
这可能适合您 (GNU sed):
sed -nE '/^6/{:a;N;s/[^\n]*/&/8;Ta;x;s/^/x/;/x{100}/{z;x;p;x};x}' file
关闭隐式打印并启用扩展正则表达式 -nE
。
从以 6
开头的行开始,收集 8 行然后交换到保持 space,递增计数器,测试计数器是否出现所需的次数(在本例中为 100 ) 如果是,则将计数器归零,换回模式 space,打印它,然后 return 到保留 space。在所有情况下 return 到模式 space.
N.B。可以更改记录中的行数(在本例中为 8)以及输出记录数(在本例中为 100)。