如何将文件夹中的每个文件移动到同名的子目录中?

如何将文件夹中的每个文件移动到同名的子目录中?

假设我的目录中有一堆文件

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不会带来任何速度优势,但它仍然比许多其他给定的解决方案短。

这不依赖于文件名的模式。

相关内容