다음과 같은 파일 구조가 있습니다.
charlie
├──this-file.foo.1
├──this-file.foo.2
└──this-file.foo.3
foxtrot
├──another-file.foo.1
├──another-file.foo.2
├──another-file.foo.3.bar
├──another-file.foo.4.baz
└──another-file.foo.5.qux
this-file.waldo
another-file.waldo
루트 폴더에 있는 모든 파일의 이름을 바꾸고 싶습니다 this-file.waldo
. another-file.waldo
하위 폴더에 .waldo 파일과 동일한 기본 이름을 가진 파일이 있는 경우 파일이 포함된 하위 폴더의 이름을 같은 이름 .waldo 파일의 이름을 다음과 같이 바꿉니다.
charlie
├──this-file.foo.1
├──this-file.foo.2
└──this-file.foo.3
foxtrot
├──another-file.foo.1
├──another-file.foo.2
├──another-file.foo.3.bar
├──another-file.foo.4.baz
└──another-file.foo.5.qux
charlie.waldo
foxtrot.waldo
하위 폴더에 동일한 기본 이름을 공유하는 파일이 있고 파일 이름을 하위 폴더와 동일한 이름으로 바꿔야 하는 경우에만 파일 이름을 바꿔야 합니다.
이 목표를 달성하는 가장 효율적인 방법은 무엇입니까?
- 항상 .waldo 파일이 있습니다.
- 기본 이름을 공유하는 파일이 없으면 일치하는 항목을 찾을 때까지 무시하고 다음 파일을 계속 진행해야 합니다.
- 파일 이름은 일반 운영 체제 파일 이름이므로 &()[]# 등이 있을 수 있습니다.
답변1
이는 다음과 같이 보일 수 있습니다:
for f (*.waldo(N)) (){ (($#)) && echo mv -- $f $1:h.waldo; } */$f:r.*(NY1)
( echo
만족할 경우 제거(모의 실행)).
덜 일반적인 zsh 기능은 다음과 같습니다.
for f (values) action
: 짧은 형식의 for 루프(perl 구문과 유사)() { body; } args
: 익명 함수$var:r
:r
oot 이름(csh/vim과 같이 확장자가 없는 부분...)$var:h
:h
ead(csh/vim과 같은 디렉터리 이름)(N)
:N
ullglob glob 한정자: 일치하는 항목이 없으면 오류를 보고하지 않습니다.(Y1)
: 첫 번째로 일치하는 glob 한정자 이후에 중지합니다.
답변2
먼저 현재 디렉토리의 모든 파일 목록을 얻습니다.
files=(*(.DoN))
그런 다음 각각에 대해 다음과 같은 작업을 수행합니다.
for file in $files; do
# get the basename
bname="${file%%.*}"
# look for matches in subfolders
typeset -a matches_in_subfolders
matches_in_subfolders=*/${bname}*
# Check whether list of matches is longer than 0
if [ ${#matches_in_subfolders[@]} -gt 0 ] ; then
# do your magic renaming here
fi
done
여러 발견을 처리하는 방법을 잘 모르기 때문에 여기서는 이름을 바꾸지 않았지만
mv -- "${file}" "${matches_in_subfolders[0]}${file#*.}"
file
이름은 해당 폴더가 포함된 첫 번째 폴더 이름과 가장 긴 확장자로 이름이 변경됩니다 ( 가 아닌 경우 .waldo
, 가 아니라 을 .foo.waldo
원한다고 가정합니다 ).charlie.foo.waldo
charlie.waldo