使用 sed 替换不同文件夹中文件中的字符串

使用 sed 替换不同文件夹中文件中的字符串

我有一个文件放置在不同的文件夹中(文件扩展名为 .mvw)。我想编写一个脚本,该脚本转到每个文件夹并用文件夹名称替换字符串(在文件 *.mvw 中)“D3PLOT_1DForce”。

文件夹结构如下-

  • XYZ_DV_L02_P01
  • XYZ_DV_L02_P02
  • XYZ_DV_L02_P03

我写了以下脚本 -

#!/bin/sh
for ii in XYZ_DV_L02* ; do
(cd "$ii")
find . -iname "*.mvw" -type f -exec sed -i "s/D3PLOT_1DForce_EffPlStrainMax_VonMisesMax/"${ii}"/g" "{}" \;
done

它可以工作并将字符串替换为文件夹的名称,但它会替换所有文件中第一个文件夹的名称。我认为 sed 不会进入 for 循环。

如何让 sed 在循环中工作,以便使用相应的文件夹名称来替换文件中的字符串?

答案1

cd命令在子 shell 中执行,因此实际上不执行任何操作。因此,您的find命令是从父目录执行的,对于 .txt 中的每个子目录名称执行一次XYZ_DV_L02*。第一次调用sed会更改所有文件中的字符串,后续调用sed不会找到该字符串,但无论如何都会执行。

尝试这个:

#!/bin/sh
for ii in XYZ_DV_L02* ; do
    find "$ii" -iname "*.mvw" -type f -exec sed -i "
      s/D3PLOT_1DForce_EffPlStrainMax_VonMisesMax/${ii}/g" "{}" +
done

感谢 Stéphane Chazelas 的编辑

虽然我只是find从问题中复制了命令,仅修复了路径,但值得解释一下这些更改:

  • ${ii}以前没有被引用,现在它是包含整个参数的引号的一部分sed
  • 使用+代替\;将导致对多个文件find执行一个sed命令,而不是对每个文件执行一个命令。

编辑

对于评论的请求,这将替换集合中的每个序列[-_a-zA-Z0-9],后跟.h3d替换文本,这是包括.mvw扩展名的文件名,这就是我理解评论的方式,但它似乎没有用。如果您想访问模式中的文本,可以使用\1。您可能需要根据您的特定需求调整该套件。

#!/bin/sh
for ii in XYZ_DV_L02* ; do
    find "$ii" -iname "*.mvw" -type f -exec sed -i -r "
      s/([-_a-zA-Z0-9]+)\.h3d/${ii}.h3d/g" "{}" +
done

答案2

尝试这个,

#!/bin/sh
for ii in XYZ_DV_L02* ; do
cd "$ii"
find . -iname "*.mvw" -type f -exec sed -i "s/D3PLOT_1DForce/"${ii}"/g" "{}" \;
cd ..
done

将目录更改为 for 循环中的第一个输入文件夹并查找文件就可以了。但是在运行下一个循环之前我们必须返回到父目录。

答案3

如果您的目录结构仅包含许多子目录,每个子目录都有.mvw您想要修改的文件,则无需使用,find因为您已经确切知道文件所在位置。

for pathname in XYZ_DV_L02*/*.mvw; do
    sed -i "s/D3PLOT_1DForce/${pathname%%/*}/g" "$pathname"
done

这将迭代.mvw指定子目录中的所有文件,并将字符串替换为目录名称。参数扩展会删除中字符串中${pathname%%/*}第一个之后的所有内容。/$pathname

测试:

$ tree
.
|-- XYZ_DV_L02_P01
|   `-- somefile.mvw
|-- XYZ_DV_L02_P02
|   `-- somefile.mvw
`-- XYZ_DV_L02_P03
    `-- somefile.mvw

3 directories, 3 files

$ cat XYZ_DV_L02_P0*/*.mvw
Hello D3PLOT_1DForce_EffPlStrainMax_VonMisesMax!
Hello D3PLOT_1DForce_EffPlStrainMax_VonMisesMax!
Hello D3PLOT_1DForce_EffPlStrainMax_VonMisesMax!

(这里运行循环)

$ cat XYZ_DV_L02_P0*/*.mvw
Hello XYZ_DV_L02_P01_EffPlStrainMax_VonMisesMax!
Hello XYZ_DV_L02_P02_EffPlStrainMax_VonMisesMax!
Hello XYZ_DV_L02_P03_EffPlStrainMax_VonMisesMax!

显然,如果您有很深的层次结构,那么您可能无论如何都需要使用,但您可以从内部而不是外部find进行循环:findfind

find XYZ_DV_L02*/ -type f -name '*.mvw' -exec sh -c '
    for pathname do
        sed -i "s/D3PLOT_1DForce/${pathname%%/*}/g" "$pathname"
    done' sh {} +

在这里,我们找到.mvw与模式匹配的任何目录下的所有文件XYZ_DV_L02*/。对于这些找到的文件,我们运行一个循环,该循环执行与本答案开头的循环相同的操作。这会将任何目录下任何位置的D3PLOT_1DForce所有文件中的字符串替换为相应的目录名称。.mvwXYZ_DV_L02*

有关的:

这个答案假设 GNUsed或其他一些实现不使用选项参数sed进行就地编辑。-i

相关内容