如何使用 bash 替换另一个文件中的字符串例如:
有一个路径:\\Hostname\example\example.txt
我想用Hostname
另一个包含 162 个主机名的文件中 162 个主机名替换 ,然后保存结果。因此总路径应该是:162 个具有不同主机名的路径 (162)
第一个文件夹是:Paths.txt(有 2 个路径):
\\Hostname\example1\example1.txt
\\Hostname\example2\example2.txt
第二个文件是:Hostname.txt(有 162 个主机名)
我试过 :
sed -i 's/Hostname/Hostname.txt/gI' Paths.txt
但结果是:
\\Hostname.txt\example1\example1.txt
\\Hostname.txt\example2\example2.txt
它没有读取文件 Hostname.txt 中的真实主机名
答案1
这不是问题的直接答案,但是为了解决这个任务,你可以使用以下循环:
while IFS= read -r hostname; do \
printf '\\\\%s\\example1\\example1.txt\n' "$hostname" >> ./hosts-new.txt; \
printf '\\\\%s\\example2\\example2.txt\n' "$hostname" >> ./hosts-new.txt; \
done < ./hosts-list.txt
复制以上几行并将它们作为单个命令(内联脚本)运行。
以下是一些解释:
hosts-new.txt
是输出文件。hosts-list.txt
是包含主机名的输入文件,每个主机名占一行。IFS= read -r hostname
(在每次循环迭代中)将读取输入文件的一行并将其赋值给我们命名的变量的值$hostname
...正如@StéphaneChazelas 在他的文章中所说的那样百科全书式的答案这是read
使用内置命令读取一行输入的规范方法。printf '\\\\%s\\example\\example.txt\n' "$hostname"
将为每一行生成所需的输出。通过\\
转义单个 的特殊含义。末尾的\
字符表示换行符。是第一个位置参数(的)值的字符串格式的占位符,即我们的变量。\n
%s
printf
$hostname
输出重定向
>>
将把每一行附加到输出文件。在最后的部分,
< ./hosts-list.txt
我们将输入文件的内容作为循环的输入while
,这由三个关键字定义while (condition); do (something); done
。因此,while
逐行读取文件,在本例中,状况是当有输入时。
这是上述的另一个版本,它可能会更快,因为它只会在循环完成后写入新文件一次。
while IFS= read -r hostname; do \
printf '\\\\%s\\example1\\example1.txt\n' "$hostname"; \
printf '\\\\%s\\example2\\example2.txt\n' "$hostname"; \
done < ./hosts-list.txt > ./hosts-new.txt
注意这里使用重定向>
(而不是>>
)来覆盖输出文件的内容。
答案2
如果您确实想从文件中读取输入路径和替换,您可以在 GNU awk 中执行如下操作:
gawk '
BEGIN {
PROCINFO["sorted_in"] = "@ind_num_asc"
}
NR==FNR {
paths[FNR] = $0
next
}
{
for(i in paths)
print gensub(/\\\\Hostname/,"\\\\"$0,"1",paths[i])
}
' Paths.txt Hostname.txt
BEGIN
如果您不关心每个主机的路径顺序,则可以省略该块。您可以安全地省略模式和替换中的\\\\
and (它们只是为了固定字符串,以防它可能在文件中其他地方出现而没有前缀的情况)。\\\\
gensub
Hostname
\\
您还可以考虑将文件的整个内容合并Paths.txt
为一个多行字符串,然后gensub
使用g
全局标志而不是循环来应用:
gawk '
NR==FNR {
paths = paths (paths ? RS : "") $0
next
}
{
print gensub(/\\\\Hostname/,"\\\\"$0,"g",paths)
}
' Paths.txt Hostname.txt
BEGIN
或者将路径文件作为块中的单个以空分隔的记录
gawk -v pathsfile="Paths.txt" '
BEGIN {
RS = "\0"
getline paths < pathsfile
RS = "\n"
}
{
printf "%s", gensub(/\\\\Hostname/,"\\\\"$0,"g",paths)
}
' Hostname.txt
或(应该可以在任何 awk 中使用)
awk '
NR==FNR {
paths = paths (paths ? RS : "") $0
next
}
{
newpaths = paths
gsub(/\\\\Hostname/,"\\\\"$0,newpaths)
print newpaths
}
' Paths.txt Hostname.txt