다른 폴더에 있는 여러 파일의 이름을 바꾸고 싶습니다. 더 구체적으로 말하자면, 파일 이름 중간에 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자 너비로 제로 패딩하려는 숫자를 얻습니다.
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
-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