다른 하위 폴더의 파일 이름 바꾸기

다른 하위 폴더의 파일 이름 바꾸기

다른 폴더에 있는 여러 파일의 이름을 바꾸고 싶습니다. 더 구체적으로 말하자면, 파일 이름 중간에 0을 추가하여 모든 파일 이름이 세 자리 숫자를 갖도록(따라서 논리적 순서로 표시되도록) 싶습니다.

좀 더 구체적으로 말하자면, 각 폴더에 400개 이상의 .nii 파일이 포함된 130개가 넘는 폴더가 있습니다. 각 .nii 파일에는 다음 패턴이 있습니다.

swu_run1_P_139_Vol_1.nii

  • P_### 범위는 P76~P277(참가자 번호)입니다.
  • Vol_### 범위는 1~405(볼륨 번호)

볼륨 범위는 1부터 405까지이므로 이는 모든 목록이 1-405가 아닌 100으로 시작함을 의미합니다. 예를 들어 100 - 101 - 102 [..] - 109 -로 시작합니다.10- 110~111 등). 이 문제를 해결하는 한 가지 방법은 파일 이름에 0을 추가하고 모든 것을 세 자리 숫자로 만드는 것입니다. 예를 들면 다음과 같습니다.

swu_run1_P_277_Vol_1.nii -> swu_run1_P_277_Vol_001.nii
swu_run1_P_277_Vol_2.nii -> swu_run1_P_277_Vol_002.nii
swu_run1_P_277_Vol_10.nii -> swu_run1_P_277_Vol_010.nii
swu_run1_P_277_Vol_120.nii -> swu_run1_P_277_Vol_120.nii

나는 유닉스/리눅스 시스템에 대한 경험이 거의 없지만 이전 스레드를 사용하여 다음 코드를 생각해 냈습니다. 두 부분으로 구성됩니다.

1. 파일 이름 중간에 0을 추가하여 여러 파일 이름을 바꿉니다.

rename Vol_ Vol_0 *Vol_[0-9].nii

하위 폴더에서 실행하면 다음과 같은 오류 메시지가 나타납니다.

Error: rename: swu_run1_P_275_Vol_1.nii: rename to swu_run1_P_275_Vol_01.nii failed: No such file or directory

이상하게도 Vol_1-9에는 0이 추가됩니다. 그러나 이미 두 자리 또는 세 자리 숫자가 있는 숫자에는 0을 추가하지 않습니다.

swu_run1_P_277_Vol_1.txt -> swu_run1_P_277_Vol_01.nii
swu_run1_P_277_Vol_10.txt -> swu_run1_P_277_Vol_10.nii
swu_run1_P_277_Vol_100.txt -> swu_run1_P_277_Vol_100.nii

표현식에 이상한 루프가 발생하는 것 같습니다(새 Vol_01을 변경하려고 시도하면서 오류 메시지가 표시됨). 두 자리/세 자리 숫자에 0을 추가하지 않는 이유는 무엇입니까?

2. .nii관련 하위 폴더에서 모든 파일을 찾은 다음 일괄 이름 바꾸기를 수행합니다.

find . -iname "*.nii" -execdir rename Vol_ Vol_0 *Vol_[0-9].nii '{}' \;

이 코드에 대한 나의 이해는 다음과 같습니다.

  • find . -iname "*.nii"현재 폴더 및 하위 폴더의 모든 .nii 파일 검색

  • -execdir현재 폴더와 하위 폴더에 다음 표현식을 적용하도록 지시합니다. 즉, 0을 추가합니다.

  • rename Vol_ Vol_0 *Vol_[0-9].nii0 추가(다음 형식 사용)텍스트에서 문자로 파일 목록)

  • '{}'파일의 경로 이름이 있습니다

  • \;-execdir 표현식을 종료할 수 있습니까?

더 많은 폴더에서 코드를 실행하려고 하면 다음과 같은 오류 메시지가 나타납니다.

Error: rename: *Vol_[0-9].nii: rename to *Vol_0[0-9].nii failed: No such file or directory

-execdir이 하위 폴더에서 실행되지 않기 때문에 오류 메시지가 나타나는 것 같은데, 이 문제를 해결하는 방법을 모르겠습니다.

쉘을 실행하기 위해 수동으로 각 하위 폴더로 이동하고 싶지 않습니다. 이 코드를 개선하고 작동하게 만드는 방법에 대한 제안 사항이 있습니까? "해당 파일이나 디렉터리가 없습니다." 오류 메시지가 나타나는 이유는 무엇입니까?

답변1

swu_run1_P_277_Vol_1.nii변수에 이름이 있으면 name그럴 ${name##*_}것입니다 1.nii(가장 긴 접두사 문자열 일치가 *_제거됨).

가져오고 삭제한 후 .nii3자 너비로 제로 패딩하려는 숫자를 얻습니다.

name=swu_run1_P_277_Vol_1.nii

number=${name##*_}
number=${number%.nii}

bash셸 에서 숫자를 제로 패드하는 가장 간단한 방법은 다음과 같습니다 printf.

printf '%.3d' "$number"    # would print 001 (with no newline)

동시에 새로운 이름을 구성할 수 있습니다.

printf '%s_%.3d.nii' "${name%_*.nii}" "$number"

printf명령은 swu_run1_P_277_Vol_001.nii원래 이름에서 일치하는 접미사 문자열을 제거하고 0으로 채워진 숫자를 추가한 다음 접미사 문자열을 추가하여 인쇄합니다._*.nii_.nii

가장 중요한 것은 결과 문자열을 인쇄할 수 있다는 것입니다.곧장새로운 변수로 printf -v newname ....

하나의 이름으로 함께 사용하세요.

name=swu_run1_P_277_Vol_1.nii

number=${name##*_}
number=${number%.nii}

printf -v newname '%s_%.3d.nii' "${name%_*.nii}" "$number"

글쎄요, 그건 단지 질문일 뿐입니다 mv "$name" "$newname".

좋습니다. 모든 관련 파일에 대해 이 작업을 어떻게 수행합니까?

모든 관련 파일이 와일드카드 패턴과 일치한다고 가정 *Vol_*.nii하면 find,

find . -type f -name '*Vol_*.nii' -exec bash -c '
    for pathname do
        dirpath=${pathname%/*}  # or: dirpath=$(dirname "$pathname")
        name=${pathname##*/}    # or: name=$(basename "$pathname")

        number=${name##*_}
        number=${number%.nii}

        printf -v newname "%s_%.3d.nii" "${name%_*.nii}" "$number"

        printf "Would rename %s --> %s\n" "$pathname" "$dirpath/$newname"
        # mv "$pathname" "$dirpath/$newname"
    done' bash {} +

bash -c여기의 인라인 스크립트는 (일반 파일임) 및 (특정 이름 있음) 조건을 find충족하는 경로 이름을 사용하여 일괄적으로 호출 됩니다. 스크립트는 이러한 경로 이름을 반복하여 파일 이름을 추출 하고 디렉토리 경로 이름을 .-type f-namenamedirpath

그런 다음 이전에 수행한 것과 동일한 작업을 수행하여 에 저장된 새 이름을 얻은 newname다음 파일 이름을 바꿉니다.

mv글쎄, 나는 안전을 위해 실제 명령을 주석 처리했습니다. 출력이 올바른지 확인하려면 먼저 한 번 실행해야 합니다. GNU 도구를 사용하는 경우 mv -b이름 충돌이 있는 경우 이를 사용하여 파일을 백업 할 수도 있습니다 .


참고로 zsh쉘에서는 와일드카드 패턴이

./**/*Vol_*.nii(n)

이 모든 이름으로 확장됩니다.번호순으로(그리고 int 하위 디렉터리로 재귀적으로 이동):

$ print -rC1 ./**/*Vol_*.nii(n)
./swu_run1_P_277_Vol_1.nii
./swu_run1_P_277_Vol_2.nii
./swu_run1_P_277_Vol_10.nii
./swu_run1_P_277_Vol_120.nii

관련 정보