逐行解析 2 个文件,在第 3 个文件中搜索和替换

Posted

技术标签:

【中文标题】逐行解析 2 个文件,在第 3 个文件中搜索和替换【英文标题】:Parse 2 files line by line, search and replace in a 3rd file 【发布时间】:2021-07-15 02:57:33 【问题描述】:

我正在尝试制作一个执行以下操作的 bash 脚本:

解析2个行数相同的文件 在第 3 个文件中搜索第 2 个文件的每一行的内容,如果匹配,它会将第 3 个文件中的内容替换为第 1 个文件对应行的内容。

更具体地说,让我们说文件内容如下所示:

文件1:

10_100test-NFV
APP_SP1 
APP_SP1 
APP_SP1 
ADmanage 
ADmanage 
ADmanage 
ADmanage 
ADmanage 
AFG 
AFG 
Alton-VNET-NFV
Alton-VNET-NFV
Apex-VNet-NFV 
Apex-VNet-NFV 

文件2:

4337c0148f79496c8bec580af6adaee1
c9d18ece507f4ac387341890a629215b
039b785080414ef3bad80def7153e56e
a5c2f415b26946eb90d927fb257fb571
466e9135208d44029843d7905bb95bf1
79a9913f25b548a3803511909d49439b
8444da0b23e14b158904433ced89889c
54d6ba8e30e947e3926e59cf813a6cc6
a5911c24f1244577930ed4fe50151ba2
13c812c9fbb748bab62598d26e8fa992
22273e68097f4323a000ca52b2e5b3e5
f4811f2a3b1f41d09925f9048fa2135f
bc58674277ac47ed84b68570ca79aa27
b2b0bf7ae4f5464690e0b753e78ad668
7eabb4119a4d4189b8f6e32d62aa998f

文件3:

00:10:01    DISK_884820fb00f946d9b36efb6dc6d00469     49.81     88.71    286.16      7.53      0.32      6.28      0.84      4.20
00:10:01    DISK_5c5a9e193b434d729873a1c96f14deff      0.65      5.20      0.00      8.00      0.00      5.27      3.41      0.22
00:10:01    DISK_db630dac761946419a174a7958d301d7     13.40     25.14     75.28      7.50      0.07      5.48      1.13      1.51
00:10:01    DISK_79a9913f25b548a3803511909d49439b      8.23      1.55     60.34      7.52      0.04      4.28      0.87      0.72
00:10:01    DISK_892f7dde836641fd84fdb790090ac40c      0.52      3.07      0.65      7.21      0.00      2.97      2.15      0.11
00:10:01    DISK_f8b9c9555f894fdc9c6526f07124d83b     82.56     70.87    573.69      7.81      0.55      6.58      0.65      5.34
00:10:01    DISK_f6b732c30176435e8bc1ed41d58bd6c8    106.63      4.69    507.36      4.80      0.54      5.02      2.00     21.37
00:10:01    DISK_c3f1181557d247e8811765e840705c16      0.19      1.49      0.00      8.00      0.00      4.08      2.29      0.04
00:10:01    DISK_bc00e5020df84ef5aae14c69aec2904c     11.64      1.49     85.53      7.47      0.04      3.57      0.69      0.80
00:10:01    DISK_85e21bfec61c498bbab3d8cbc925d5ca      8.08      3.25     54.15      7.11      0.32     39.87      1.06      0.86
00:10:01    DISK_efb1e9bc83304ed3aee855a4ac7747b1      0.28      1.51      0.46      7.05      0.00      3.67      2.10      0.06
00:10:01    DISK_eb2ff849ddf5439e95ca5df2820e525d      6.60      1.56     27.56      4.41      0.03      4.22      3.43      2.27

运行脚本后,file3 应该是这样的:

00:10:01    DISK_AFG     49.81     88.71    286.16      7.53      0.32      6.28      0.84      4.20
00:10:01    DISK_Alton-VNET-NFV      0.65      5.20      0.00      8.00      0.00      5.27      3.41      0.22
00:10:01    DISK_ADmanage     13.40     25.14     75.28      7.50      0.07      5.48      1.13      1.51
00:10:01    DISK_79a9913f25b548a3803511909d49439b      8.23      1.55     60.34      7.52      0.04      4.28      0.87      0.72
00:10:01    DISK_10_100test-NFV       0.52      3.07      0.65      7.21      0.00      2.97      2.15      0.11
00:10:01    DISK_AFG     82.56     70.87    573.69      7.81      0.55      6.58      0.65      5.34
00:10:01    DISK_f6b732c30176435e8bc1ed41d58bd6c8    106.63      4.69    507.36      4.80      0.54      5.02      2.00     21.37
00:10:01    DISK_c3f1181557d247e8811765e840705c16      0.19      1.49      0.00      8.00      0.00      4.08      2.29      0.04
00:10:01    DISK_ADmanage     11.64      1.49     85.53      7.47      0.04      3.57      0.69      0.80
00:10:01    DISK_85e21bfec61c498bbab3d8cbc925d5ca      8.08      3.25     54.15      7.11      0.32     39.87      1.06      0.86
00:10:01    DISK_efb1e9bc83304ed3aee855a4ac7747b1      0.28      1.51      0.46      7.05      0.00      3.67      2.10      0.06
00:10:01    DISK_Apex-VNet-NFV      6.60      1.56     27.56      4.41      0.03      4.22      3.43      2.27

到目前为止,我写了这个,但它没有做任何事情:

#!/bin/bash

read -p "Please enter the path to the first file: " uuids 
read -p "Please enter the path to the second file: " vms
read -p "Please enter the path to the 3rd file: " sar

while read -r vm; do
     while read -r uuid; do 
          grep -o -h -m 1 "$uuid" $sar
          if [ $? -eq 0 ]  
          then
              sed -i "s/$uuid/$vm/g" $sar
              break
          else
              break
          fi
     done < "$uuids"
done < "$vms"

【问题讨论】:

请更新问题,使样本输入与所需输出匹配;正如当前所写的那样,您在所需输出中所做的许多更改...它们与您的示例输入中的任何内容都不匹配...这可能会导致混淆,因为我们可能想出的任何代码都无法根据给定的样本输入生成所需的输出;另外,您能否通过指示这些文件的大小来更新问题(对于每个文件:行数和总 MBytes),因为这可能会影响任何提议的代码(例如,所有内容是否都可以放入内存) 谢谢@markp-fuso,你是对的。文件 1 和 2 的大小约为 40-80kb,2566 行,文件 3 约为 3-4MB,25-30000 行。 【参考方案1】:

在第三个文件中搜索第二个文件每一行的内容

但您在第三个文件中搜索第一个文件的行:

read -p "Please enter the path to the first file: " uuids 
read -p "Please enter the path to the second file: " vms
read -p "Please enter the path to the 3rd file: " sar

# [...] loops and stuff
grep -o -h -m 1 "$uuid" $sar
# [...] loops and stuff

您可能想交换 vmsuuids。 此外,我会使用这种更有效的方法来代替循环:

read -p "Please enter the path to the first file: " vms 
read -p "Please enter the path to the second file: " uuids
read -p "Please enter the path to the 3rd file: " sar

sed -i "$(paste -d/ "$uuids" "$vms" | sed 's|^.*$|s/&/|')" "$sar"

仅当文件 1 ($vms) 和 2 ($uuids) 不包含诸如 .*\/ 之类的元字符时,上述命令才有效。

此外,文件 1 和 2 的组合必须小于 ARG_MAX。对于较大的文件,sed 脚本必须从文件中读取:

paste -d/ "$uuids" "$vms" | sed 's|^.*$|s/&/|' > sedCommands
sed -i -f sedCommands "$sar"

【讨论】:

感谢@Socowi 的回答,我尝试应用您的解决方案,但出现错误:./sed.sh: line 7: /usr/bin/sed: Argument list too long 感谢您的反馈。似乎您的实际文件比您示例中的文件大得多。我添加了一个解决方法。 测试了您的解决方法并且很好。你能解释一下 sed 命令 sed 's|^.*$|s/&/|' ? 当然。 s|A|B|A 替换为 B^.*$ 匹配整行。 &amp; 是被替换的东西。因此,sed 's|^.*$|s/&amp;/|' 会在 s/ 前面加上 / 到输入中的每一行。 知道了,谢谢。因此,在 sed 表达式中,您使用了 | 而不是 /,因此 / 可以被解释为替换字符,而不是 sed 语法的一部分。【参考方案2】:

修改了file2 的副本以允许匹配file3 示例中的某些行:

$ cat file2
884820fb00f946d9b36efb6dc6d00469
c9d18ece507f4ac387341890a629215b
db630dac761946419a174a7958d301d7
a5c2f415b26946eb90d927fb257fb571
892f7dde836641fd84fdb790090ac40c
79a9913f25b548a3803511909d49439b
f6b732c30176435e8bc1ed41d58bd6c8
54d6ba8e30e947e3926e59cf813a6cc6
c3f1181557d247e8811765e840705c16
13c812c9fbb748bab62598d26e8fa992
85e21bfec61c498bbab3d8cbc925d5ca
f4811f2a3b1f41d09925f9048fa2135f
eb2ff849ddf5439e95ca5df2820e525d
b2b0bf7ae4f5464690e0b753e78ad668
7eabb4119a4d4189b8f6e32d62aa998f

使用pasteawk 自动生成一些sed 命令的想法:

$ awk 'printf "s/%s/%s/\n", $1, $2' < <(paste file2 file1) > list_of_sed_cmds
$ cat list_of_sed_cmnds
s/884820fb00f946d9b36efb6dc6d00469/10_100test-NFV/
s/c9d18ece507f4ac387341890a629215b/APP_SP1/
s/db630dac761946419a174a7958d301d7/APP_SP1/
s/a5c2f415b26946eb90d927fb257fb571/APP_SP1/
s/892f7dde836641fd84fdb790090ac40c/ADmanage/
s/79a9913f25b548a3803511909d49439b/ADmanage/
s/f6b732c30176435e8bc1ed41d58bd6c8/ADmanage/
s/54d6ba8e30e947e3926e59cf813a6cc6/ADmanage/
s/c3f1181557d247e8811765e840705c16/ADmanage/
s/13c812c9fbb748bab62598d26e8fa992/AFG/
s/85e21bfec61c498bbab3d8cbc925d5ca/AFG/
s/f4811f2a3b1f41d09925f9048fa2135f/Alton-VNET-NFV/
s/eb2ff849ddf5439e95ca5df2820e525d/Alton-VNET-NFV/
s/b2b0bf7ae4f5464690e0b753e78ad668/Apex-VNet-NFV/
s/7eabb4119a4d4189b8f6e32d62aa998f/Apex-VNet-NFV/

现在对file3 应用这些sed 命令:

$ sed -f list_of_sed_cmnds file3
00:10:01    DISK_10_100test-NFV     49.81     88.71    286.16      7.53      0.32      6.28      0.84      4.20
00:10:01    DISK_5c5a9e193b434d729873a1c96f14deff      0.65      5.20      0.00      8.00      0.00      5.27      3.41      0.22
00:10:01    DISK_APP_SP1     13.40     25.14     75.28      7.50      0.07      5.48      1.13      1.51
00:10:01    DISK_ADmanage      8.23      1.55     60.34      7.52      0.04      4.28      0.87      0.72
00:10:01    DISK_ADmanage      0.52      3.07      0.65      7.21      0.00      2.97      2.15      0.11
00:10:01    DISK_f8b9c9555f894fdc9c6526f07124d83b     82.56     70.87    573.69      7.81      0.55      6.58      0.65      5.34
00:10:01    DISK_ADmanage    106.63      4.69    507.36      4.80      0.54      5.02      2.00     21.37
00:10:01    DISK_ADmanage      0.19      1.49      0.00      8.00      0.00      4.08      2.29      0.04
00:10:01    DISK_bc00e5020df84ef5aae14c69aec2904c     11.64      1.49     85.53      7.47      0.04      3.57      0.69      0.80
00:10:01    DISK_AFG      8.08      3.25     54.15      7.11      0.32     39.87      1.06      0.86
00:10:01    DISK_efb1e9bc83304ed3aee855a4ac7747b1      0.28      1.51      0.46      7.05      0.00      3.67      2.10      0.06
00:10:01    DISK_Alton-VNET-NFV      6.60      1.56     27.56      4.41      0.03      4.22      3.43      2.27

一旦满足 OP 要求,脚本就可以按需要运行,-i 标志可以添加到 sed -f .... 调用中,以使用新的修改更新 file3

注意:正如 Socowi 所说,这假定 file1file2 中没有元字符;如果有元字符,那么我们需要更完整的样本数据集才能提出可行的解决方案。

【讨论】:

这适用于@markp-fuso,而且速度非常快。对于我在这种特殊情况下的需要,这已经绰绰有余了。谢谢! re: speed ... while/while 双循环将需要很长时间(呃)如果仅仅是因为file3(又名$sar)的次数太多重读(grepsed)并重写(sed);在这个答案中,我们只需要对file3 进行一次读取/重写,因此对于任何可观的模式替换量,速度差异都应该是显而易见的

以上是关于逐行解析 2 个文件,在第 3 个文件中搜索和替换的主要内容,如果未能解决你的问题,请参考以下文章

python读取文本文件,如何将每行最后一个特定字符替换?

如何优化打开和读取多次相同文件的python脚本?

数据结构与算法之深入解析“第K个语法符号”的求解思路与算法示例

在文本文件中搜索和替换字符串

Python文件搜索替换

逐行读取文本文件并将这些行放入Java中的列表中