Как сделать сценарий оболочки для перемещения файлов в отдельные папки на основе имени файла?

Я хочу автоматизировать перемещение файлов эпизодов телешоу в отдельные каталоги для каждого эпизода.

По сути, в папке, в которой я хочу запустить скрипт, у меня есть список файлов. Например: tvshow.2009.S01E01.episodename1.mkv,tvshow.2009.S01E02.episodename2.mkv, tvshow.2009.S01E03.episodename3.mkvи т. д. и пустые каталоги в формате E01, E02, E03и т. д.

На этом этапе я перемещал файлы вручную с помощью автозаполнения вкладки в командной строке. По сути, я печатаю:

mv t

а затемнажмите клавишу Tab, чтобы автоматически завершить

mv tv.show.2009.S01E0

затем введите 1 и снова нажмите Tab, чтобы добраться до

mv tv.show.2009.S01E01.episodename1.mkv 

затем я набираю правильную папку, чтобы добраться до

mv tv.show.2009.S01E01.episodename1.mkv E01/

и затем нажмите Enter, чтобы завершить команду. Я должен повторить шаги для такого же количества эпизодов, что и в исходном каталоге, и, учитывая тот факт, что я, по сути, повторяю те же самые шаги и просто повторяю номер эпизода, это кажется идеальным использованием цикла for в сценарии.

Проблема заключается в том, что файлы не всегда имеют один и тот же формат и, очевидно, будут иметь разные имена в зависимости от шоу. Что постоянно, хотя это S##E## всегда будет отображаться в имени файла, и мне нужно только использовать E## определить правильный файл и переместить его в папку, которая уже существует и точно соответствует E## из файла.

Я опытный программист, но еще не работал со скриптами оболочки. Моя мысль состоит в том, чтобы, возможно, перебрать все существующие E## папки, найдите файл, который содержит это E## последовательность, а затем переместите этот файл в папку. К сожалению, я не уверен, правильно ли делать это с помощью скрипта, который я могу запустить из командной строки.

Будет ли кто-нибудь иметь предложенный план подхода или сможет указать мне на ресурс, к которому я мог бы обратиться за помощью?

3 ответа

Решение

Вы можете использовать это из каталога, где у вас есть файлы и пустые каталоги, предполагая, что ваши файлы имеют .mkv расширение:

for file in *.mkv;do mv "$file" "$(echo $file | sed -E 's/.*S[0-9]+(E[0-9]+).*/\1/')";done

В выше for петли, mv используется для перемещения каждого файла ("$file") к соответствующему каталогу эпизодов ("$(echo $file | sed -E 's/.*S[0-9]+(E[0-9]+).*/\1/')"). Вот, sed используется для извлечения эпизода из имени файла. По сути, это соответствует S##E## часть имени файла с использованием регулярного выражения (.*S[0-9]+(E[0-9]+).*), из которого сохраняется только часть внутри скобок (\1 в конце sed команда).

Исходная структура файла:

.
├── E01
├── E02
├── E03
├── E04
├── E05
├── tv.show.2009.S01E01.episodename1.mkv
├── tv.show.2009.S01E02.episodename1.mkv
├── tv.show.2009.S01E03.episodename1.mkv
├── tv.show.2009.S01E04.episodename1.mkv
└── tv.show.2009.S01E05.episodename1.mkv

Результат:

.
├── E01
│   └── tv.show.2009.S01E01.episodename1.mkv
├── E02
│   └── tv.show.2009.S01E02.episodename1.mkv
├── E03
│   └── tv.show.2009.S01E03.episodename1.mkv
├── E04
│   └── tv.show.2009.S01E04.episodename1.mkv
└── E05
    └── tv.show.2009.S01E05.episodename1.mkv

Хотя вы упоминаете, что вы уже создали каталоги эпизодов, вы можете создать их, а также переместить файлы в них, изменив указанную выше команду. Модификация просто добавляет mkdir "$(echo $file | sed -E 's/.*S[0-9]+(E[0-9]+).*/\1/')" к команде (echo часть такая же, как в mv до). Таким образом, команда для создания каталогов и перемещения файлов в них:

for file in *.mkv;do mkdir "$(echo $file | sed -E 's/.*S[0-9]+(E[0-9]+).*/\1/')" && mv "$file" "$(echo $file | sed -E 's/.*S[0-9]+(E[0-9]+).*/\1/')";done

Исходная файловая структура:

.
├── tv.show.2009.S01E01.episodename1.mkv
├── tv.show.2009.S01E02.episodename1.mkv
├── tv.show.2009.S01E03.episodename1.mkv
├── tv.show.2009.S01E04.episodename1.mkv
└── tv.show.2009.S01E05.episodename1.mkv

Результат:

.
├── E01
│   └── tv.show.2009.S01E01.episodename1.mkv
├── E02
│   └── tv.show.2009.S01E02.episodename1.mkv
├── E03
│   └── tv.show.2009.S01E03.episodename1.mkv
├── E04
│   └── tv.show.2009.S01E04.episodename1.mkv
└── E05
    └── tv.show.2009.S01E05.episodename1.mkv

Вот решение, которое я придумал благодаря другим предоставленным ответам

#!/bin/bash

for f in *.mkv *.mp4 *.wmv; do
        if [ -f "$f" ] # does file exist?
        then
                dir=$(echo "$f" | grep -o "E[0-9][0-9]" | head -1) # extract first E## from filename
                if [ "$dir" ] # check if string found
                then
                        mkdir -p "$dir"  # create dir
                        mv "$f" "$dir"     # move file into new dir
                else
                        echo "INCORRECT FILE FORMAT: \""$f"\"" # print error if file format is unexpected
                fi
        fi
done

Мне пришлось добавить некоторую проверку ошибок, чтобы поймать любые файлы, которые неправильно отформатированы, и для файлов с двумя эпизодами, в которых имя файла имеет две совпадающие строки E## (например, tvshow.S01E20E21.mkv). Для файлов с двумя эпизодами он создаст каталог только для первого номера эпизода и переместит туда файл. Обратите внимание, что этот скрипт сделает E## каталоги, так как это упрощает использование одного сценария для всего.

Я думаю, более или менее это может работать для вас:

#!/bin/bash

for f in *.mkv *.mp4 *.wmv; do # add the extensions you want
  dir=$(echo "$f" | grep -o "S[0-9][0-9]E[0-9][0-9]")
  mkdir -p $dir
  mv $f $dir
done

Если вы хотите запустить скрипт только один раз, вы можете скопировать пути к папке в файл, давайте назовем его list:

/path/to/seriesX
/path/to/seriesY
/path/to/seriesZ

И тогда в "корневой" папке скрипт:

#!/bin/bash

mapfile -t array < list
for d in "${array[@]}"; do
  for f in "$d"/*.mkv; do
    dir="$(echo "$f" | grep -o "S[0-9][0-9]E[0-9][0-9]")"
    mkdir -p "$d"/"$dir"
    mv "$f" "$d"/"$dir"/
  done
done

Мне кажется, что вы пытаетесь просто скопировать все E01 в папку E01, E02 в папку E02 и т. Д. И т. Д., Если это так, сценарий bash, как это должно работать

#!/bin/bash

cd $(dirname $0)

for orig_filename in ./mkvfiles/*.mkv; do
    dirname="$(dirname $orig_filename)"
    filename=${orig_filename##*/}
    series=${filename%.*}
    episode=${orig_filename}

    [[ $episode =~ [eE][0-9][0-9] ]]
    epi="${BASH_REMATCH[0]}"
    if [ -n "$epi" ]; then
        echo ${epi^^}
        [ ! -d ${epi^^} ] && mkdir -p ${epi^^} || :
        /bin/cp $orig_filename ${epi^^}/$filename
    fi

done

Сценарий просто перебирает все файлы, фильтруя их по Exx (где xx - число), и создает / копирует файл в соответствующую папку.

Вам, вероятно, также придется изменить./mkvfiles/*.mkv

Другие вопросы по тегам