상위 디렉터리를 기반으로 파일 이름 바꾸기

상위 디렉터리를 기반으로 파일 이름 바꾸기

예를 들어 이라는 홈 디렉터리가 있습니다 main. 이 홈 디렉터리에는 몇 개의 폴더가 있고 그 안에는 ccc ddd및 이라는 이름의 세 개의 폴더가 있는데 lll, 이 폴더들만 찾아서 처리하고 싶습니다. 각 하위 폴더에는 세 개의 하위 폴더 모두에 동일한 이름을 가진 폴더가 있으므로 ccc ddd lll하위 폴더에는 동일한 이름의 폴더가 포함됩니다.

그런 다음 그 안의 각 하위 폴더에는 this 등과 ccc ddd lll같은 특정 이름을 가진 여러 개의 파일이 있습니다 .c_000 d_000 l_000c_001 d_001 l_001

내가 한 첫 번째 일은 아래와 같이 파일 이름의 시작 부분에 두 개의 상위 디렉터리가 추가되도록 파일 이름을 바꾸는 것이었습니다 ccc_foo1_c_000 ddd_foo1_d_000 lll_foo1_l_000. 스크립트에서 이 작업을 수행하는 방법을 제안할 수 있는 사람이 있는지 물었습니다 .sh.

내 홈 폴더의 간단한 트리 구조는 다음과 같습니다.

.
`-- main
    |-- ccc
    |   `-- foO1
    |   |    |-- c_000
    |   |    `-- c_001
    |   |
         -- foo2
    |       |-- c_000
    |       `-- c_001
    |   
    |   
    |-- ddd
    |   `-- foO1
    |   |    |-- d_000
    |   |    `-- d_001
    |   |
         -- foo2
    |       |-- d_000
    |       `-- d_001
    |-- lll
    |      `-- foO1
    |  |    |-- l_000
    |  |    `-- l_001
    |  |
    |   -- foo2
    |      |-- l_000
    |      `-- l_001
    |
    |-- aaa
    |-- bbb

답변1

다음을 수행할 수 있습니다.

for dir in ccc ddd lll; do 
    find "main/$dir" -type f -print0 | 
        while IFS= read -r -d '' f; do 
            dd=$(dirname "$f")
            new="${f/main\/}"
            new="${new//\//_}" 
            mv "$f" "$dd"/"$new"
        done
done

위 스크립트를 완료하면 파일은 다음과 같습니다.

.
`-- main
    |-- ccc
    |   |-- fo01
    |   |   |-- ccc_fo01_c_000
    |   |   `-- ccc_fo01_c_001
    |   `-- fo02
    |       |-- ccc_fo02_c_000
    |       `-- ccc_fo02_c_001
    |-- ddd
    |   |-- fo01
    |   |   |-- ddd_fo01_d_000
    |   |   `-- ddd_fo01_d_001
    |   `-- fo02
    |       |-- ddd_fo02_d_000
    |       `-- ddd_fo02_d_001
    `-- lll
        |-- fo01
        |   |-- lll_fo01_l_000
        |   `-- lll_fo01_l_001
        `-- fo02
            |-- lll_fo02_l_000
            `-- lll_fo02_l_001

설명하다

  • for dir in ccc ddd lll; do ...; done: 이 세 개의 디렉토리 이름에 대해서만 이 작업을 수행하고 개별적으로 $dir.
  • find "main/$dir" -type f -print0 |type f: ( ) 안의 모든 파일을 찾아 빈 문자열( )로 구분하여 인쇄하여 파일/디렉터리 이름에 개행 문자가 포함되어 있어도 제대로 작동하는지 확인합니다 main/$dir.-print0
  • while IFS= read -r -d '' f; do: 이는 결과를 반복하여 find각 결과를 로 저장합니다 $f. 백슬래시가 특별히 처리되지 않고 null로 구분된 입력을 읽을 수 있도록 IFS=공백을 깨는 것을 피해야 합니다 .-r-d ''
  • dd=$(dirname "$f"): $ddNow는 현재 파일이 위치한 디렉터리입니다. 예를 들어, main/ccc/fo01.
  • new="${f/main\/}": 쉘을 사용하고 있습니다.문자열 연산main/파일 경로에서 문자열을 제거하는 기능.
  • new="${new//\//_}":위에서 언급했듯이 이제 모든 것을 밑줄로 바꿉니다 /. 그러면 비슷한 문자열이 생성됩니다 ccc_fo01_c000.
  • mv "$f" "$dd"/"$new": 마지막으로 원본 파일 의 $f이름 을 $dd/$new.$dd$new

실제로 이 작업을 수행하기 전에 테스트하기 echo전에 추가하는 것이 좋습니다 mv.

답변2

이것은 파일을 반복하고 이름의 디렉터리 부분을 구문 분석하여 하나씩 이름을 바꾸는 간단한 POSIX 셸 솔루션입니다.

for x in ccc/*/* ddd/*/* lll/*/*; do
  dir2=${x%/*}; dir1=${dir2%/*}; dir2=${dir2#"$dir1"}
  mv -- "$x" "${x%/*}/${dir1}_${dir2}_${x##*/}"
done

Bash에서는 다음을 사용할 수 있습니다.매개변수 확장파일 이름 구문 분석을 방지하기 위한 문자열 대체 기능입니다.

for x in ccc/*/* ddd/*/* lll/*/*; do
  mv -- "$x" "${x%/*}/${x//\//_}"
done

zsh에서는 사용할 수 있습니다zmv패턴에 따라 파일 이름을 바꿉니다.

autoload -U zmv
zmv '(ccc|ddd|lll)/(*)/(*)' '$1/$2/${1}_${2}_$3'

답변3

소프트 코딩된 솔루션의 경우 디렉터리에서 실행됩니다 main.

#!/bin/bash

for f in $(find . -name '*_00*'); do
    mv "$f" "$(dirname "$f")/$(dirname "${f:2}" | tr "/" "_")_$(basename $f)"
done

이는 모든 디렉토리를 재귀적으로 탐색하여 패턴이 포함된 모든 파일을 찾아야 합니다 *_00*. 각 파일은 경로( $(dirname $"f")), 밑줄과 제거된 처음 두 문자를 포함하는 변환된 경로( $(dirname "${f:2}" | tr "/" "_")), 원본 파일 이름 자체( )의 $(basename $f)조합을 사용하여 개별적으로 이름이 변경됩니다 .

관련 정보