sedを使用して別のフォルダ内のファイルの文字列を置き換える

sedを使用して別のフォルダ内のファイルの文字列を置き換える

別のフォルダにファイルがあります(ファイル拡張子.mvw)。各フォルダに移動して、「D3PLOT_1DForce」文字列(* .mvwファイルにあります)をフォルダ名に置き換えるスクリプトを作成したいと思います。

フォルダ構造は次のとおりです -

  • 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コマンドはサブシェルで実行されるため、実際には何もしません。したがって、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
  • +代わりに、各ファイルに対して1つのコマンドではなく、複数のファイルに対して1つのコマンドが実行され\;ます。findsed

編集する

コメントリクエストでは、コレクション内のすべてのシーケンス[-_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

関連情報