![使用 sed 将多次出现的单词替换为列表中的单词](https://linux22.com/image/157630/%E4%BD%BF%E7%94%A8%20sed%20%E5%B0%86%E5%A4%9A%E6%AC%A1%E5%87%BA%E7%8E%B0%E7%9A%84%E5%8D%95%E8%AF%8D%E6%9B%BF%E6%8D%A2%E4%B8%BA%E5%88%97%E8%A1%A8%E4%B8%AD%E7%9A%84%E5%8D%95%E8%AF%8D.png)
我有一个文件,其中包含多次出现的行的列表
output = filename
output = filename
output = filename
output = filename
我在 txt 文件中还有一个按时间顺序排列的文件名列表,我想用它来filename
按以下顺序替换出现的内容
2d_slv_Nx.19800111.SUB.nc
2d_slv_Nx.19800213.SUB.nc
2d_slv_Nx.19800322.SUB.nc
2d_slv_Nx.19800510.SUB.nc
我想要以下输出
output = 2d_slv_Nx.19800111.SUB.nc
output = 2d_slv_Nx.19800213.SUB.nc
output = 2d_slv_Nx.19800322.SUB.nc
output = 2d_slv_Nx.19800510.SUB.nc
答案1
$ cat tmplate.sh
output = filename
output = filename
output = filename
output = filename
$ cat mkrepl.sh
while read fname
do
sed -i -e "0,/filename/s/filename/$fname/" tmplate.sh
done < tmplate.sh
$
Bash 脚本:从 tmplate.sh 读取行,将每一行提取到变量中fname
,然后sed
使用 bash 替换运行。
使用sed
,
- -i 内联编辑
- -e 表达式:
使用范围从
- 0 到 /filename/ 上的行,(从第 0 行开始使 sed 在第一次替换后停止)。
- 替换
filename
为$fname
答案2
这很容易用 来解决awk
。
sed
与循环使用相比,此解决方案仅读取输入文件并写入输出文件一次,并且仅使用一个进程。对于较长的文件名列表,这会更快。
假设调用了包含文件名的文件filenames
并且调用了包含要修改的行的输入input
,您可以使用
awk 'NR == FNR {name[i++]=$0;next} /^output = filename$/ { $3 = name[j++]; } 1' filenames input > output
解释:
该条件NR == FNR
仅适用于第一个文件。name[i++]=$0;
将行保存在数组中name
,next
跳过对此行的进一步处理。 (也可以使用name[NR]=$0;next
。)
/^output = filename$/
匹配要替换的行,$3 = name[j++];
用数组中的名称替换第三个字段。我使用了一个新的索引,j
而不是i
再次从 0 开始计数。
1
是具有隐式默认操作的“始终为真”条件print
笔记:如果要修改的行在您的实际输入中看起来不同,则脚本可能无法工作。对于文件filenames
包含的数据少于要替换的行数的情况,不会进行错误处理。