디렉토리에 여러 개의 파일이 있다고 가정해 보겠습니다.
filename-1.ext1
filename-1.ext2
filename-1.ext3
filename-2.ext1
filename-2.ext2
filename-2.ext3
filename-3.ext1
filename-3.ext2
filename-3.ext3
그런 다음 파일(파일 이름은 있지만 확장자는 없음)과 동일한 이름의 동일한 디렉토리에 하위 디렉토리를 만들고 다음과 같이 이동하려고 합니다.
filename-1
├──filename-1.ext1
├──filename-1.ext2
└──filename-1.ext3
filename-2
├──filename-2.ext1
├──filename-2.ext2
└──filename-2.ext3
filename-3
├──filename-3.ext1
├──filename-3.ext2
└──filename-3.ext3
이를 달성하는 가장 효율적인 방법은 무엇입니까?
편집: ext1, ext2, ext3은 .foo, .bar, .top, .coffee 등과 같은 세 가지 고유한 파일 이름을 나타 내기 위한 것입니다. 파일 이름이 비슷한 것은 아닙니다.
답변1
를 사용하고 있으므로 zsh
다음과 같이 수행할 수 있습니다.
for name (*.ext<->(.)) mkdir -p -- $name:r && mv -- $name $name:r
또는 더 친숙한 긴 형태의 루프를 사용 for
하여
for name in *.ext<->(.); do
mkdir -p -- $name:r &&
mv -- $name $name:r
done
*.ext<->
이는 임의의 숫자 와 일치하는 패턴과 일치하는 모든 일반 파일을 반복합니다 <->
. (.)
일반 파일만 일치하도록 강제하는 glob 한정자입니다 . *.*(.)
점이 포함된 일반 파일의 파일 이름과 일치시키려면 전체 패턴을 다음으로 변경하십시오 . 나중에 파일 이름 확장자를 제거하려면 점이 있어야 합니다. 느슨한 패턴보다는 더 엄격한 패턴을 사용하려면 다음과 같은 것을 사용하세요 filename-<->.ext<->(.)
. 이 패턴을 사용하려면 문자열로 시작하는 이름을 일치시키려는지 알아야 합니다 filename-
.
확장 $name:r
하면 와 동일한 값이 생성되지만 $name
확장자는 없습니다(즉, 값의 "루트"만).
우리는 --
두 옵션 모두에 옵션의 끝을 알리고 대시로 시작하는 이름이 옵션으로 오인되는 것을 방지하기 위해 mkdir
사용 합니다.mv
답변2
와 함께 zmv
:
autoload -Uz zmv # best in ~/.zshrc
mkmv() { mkdir -p -- $2:h && mv -- "$@"; }
zmv -P mkmv -n '(*).ext<->(#q.)' '$1/$f'
(만족하면 제거 -n
).
그렇게 하면 zmv
의 건전성 검사로부터 이익을 얻을 수 있습니다.
답변3
for
bash 및 zsh 쉘 모두와 호환되는 이 루프를 사용하십시오 .
for file in *.*; do
[ -f "$file" ] &&
mkdir -p -- "${file%.*}" &&
mv -- "$file" "${file%.*}/"
done
-p
옵션을 사용하면mkdir
파일이 존재하는지 확인합니다. 오류가 발생하지 않습니다.%.*
파일 이름에서 확장자를 제거합니다.
답변4
GNU 병렬(제가 이제 막 그 강력함을 깨닫기 시작한 도구)을 사용하면 다음과 같습니다.
ls | parallel 'mkdir -p {.}; mv -i {} {.}'
이것은 어떤 식으로든 CPU에 국한되지 않기 때문에 parallel
속도상의 이점을 제공하지는 않지만 다른 솔루션보다 여전히 짧습니다.
그리고 이것은 파일 이름의 패턴에 의존하지 않습니다.