假設我的目錄中有一堆文件
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 shell 相容的循環:
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
不會帶來任何速度優勢,但它仍然比許多其他給定的解決方案短。
這不依賴檔案名的模式。