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.
  • +대신 사용하면 각 파일에 대해 하나 의 명령이 아닌 여러 파일에 대해 하나의 명령이 실행 \;됩니다 .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*

관련된:

이 답변은 GNU sed또는 다른 구현이 sed내부 편집에 옵션 인수를 사용하지 않는다고 가정합니다.-i

관련 정보