Как переместить каждый файл из папки в подкаталог с тем же именем?

Как переместить каждый файл из папки в подкаталог с тем же именем?

Допустим, у меня есть куча файлов в каталоге.

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 parallel (инструмента, мощь которого я только начинаю осознавать):

ls | parallel 'mkdir -p {.}; mv -i {} {.}'

Поскольку это никак не связано с процессором, я полагаю, что это parallelне даст никаких преимуществ в скорости, но это все равно короче, чем многие другие приведенные решения.

И это не зависит от шаблона имен файлов.

Связанный контент