如何使用 bash 替换另一个文件中的字符串

如何使用 bash 替换另一个文件中的字符串

如何使用 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使用内置命令读取一行输入的规范方法

    • 关键在于read从一行(可能是反斜杠连续的)读取单词,其中单词是$IFS分隔符,并且可以使用反斜杠来转义分隔符(或连续行)。因此read应该调整命令来读取行。

    • IFS=改变内部字段分隔符空字符串,因此我们保留结果中的前导和尾随空格。

    • 选项-r-raw 输入 - 禁用读取数据中的反斜杠转义和行继续的解释(参考)。

  • printf '\\\\%s\\example\\example.txt\n' "$hostname"将为每一行生成所需的输出。通过\\转义单个 的特殊含义。末尾的\字符表示换行符。是第一个位置参数(的)值的字符串格式的占位符,即我们的变量。\n%sprintf$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 (它们只是为了固定字符串,以防它可能在文件中其他地方出现而没有前缀的情况)。\\\\gensubHostname\\

您还可以考虑将文件的整个内容合并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

相关内容