
다른 폴더에 있는 여러 파일의 이름을 바꾸고 싶습니다. 더 구체적으로 말하자면, 파일 이름 중간에 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].nii
0을 추가합니다(다음 형식을 사용하여텍스트에서 텍스트로 파일 목록)'{}'
파일의 경로 이름이 있습니까?\;
-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
(가장 긴 접두사 문자열 일치가 *_
제거됨).
이를 취하고 제거하면 .nii
3자 너비로 0으로 채우려는 숫자가 남습니다.
name=swu_run1_P_277_Vol_1.nii
number=${name##*_}
number=${number%.nii}
셸 에서 bash
숫자를 0으로 채우는 가장 쉬운 방법은 다음을 사용하는 것입니다 printf
.
printf '%.3d' "$number" # would print 001 (with no newline)
동시에 새 이름을 구성할 수 있습니다.
printf '%s_%.3d.nii' "${name%_*.nii}" "$number"
해당 명령은 원래 이름과 일치하는 접미사 문자열을 제거하고 0으로 채워진 숫자를 추가한 다음 접미사 문자열을 printf
인쇄하여 인쇄합니다 .swu_run1_P_277_Vol_001.nii
_*.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"
.
좋아요, 그러면 모든 관련 파일에 대해 어떻게 해야 할까요?
모든 관련 파일이 globbing 패턴 과 일치한다고 가정하고 *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
-name
name
dirpath
그런 다음 이전에 수행한 것과 동일한 작업을 수행하여 에 저장되는 새 이름에 도달한 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