Вопрос: Рекурсивно zip-файлы в .cbz-файлы на основе папки в командной строке


Я пытаюсь понять, как написать сценарий для автоматизации создания файлов .cbz из изображений в папках на OSX.

Дерево каталогов будет выглядеть так:

/toplevel/
cbz/
comics/
    Comic1/
        comic1file1.jpg
        comic1file2.gif
        comic1file3.png
    Comic2/
        comic2file1.jpg
        comic2file2.gif
    Publisher/
            Comic3/
                comic3file1.jpg
                comic3file2.gif
                comic3file3.png
            Comic4/
                comic4file1.jpg
                comic4file2.gif

И то, что я хотел бы сделать, - запустить скрипт, который найдет любую папку, содержащую фактические файлы, а не вложенные папки, и переустановит ее, переименуйте ее из .zip в .cbz и переместите файл .cbz в папку / cbz на верхнем уровне. Любая папка, содержащая вложенные папки, не должна содержать никаких файлов, поэтому это может быть полезно. Также я не ожидаю, что когда-либо будут подпапки глубже, чем показано в примере выше.

Где я нахожусь: этот фрагмент просмотрит папку и создаст .cbz-файлы для каждой подпапки.

for dir in `ls`; do zip $dir $dir/*; mv $dir*zip $dir.cbz; done

Я также нашел некоторые фрагменты, которые будут делать что-то похожее на каждую подпапку под выбранной папкой, но у меня были разные результаты, и мне было бы очень интересно узнать лучший способ выполнить операцию только в папках. Также у меня нет НИКАКОЙ подсказки относительно того, как я должен проверить, содержит ли данная папка подпапки или файлы. (Я предполагаю, что в идеале я должен включать проверки, чтобы убедиться, что есть оба, но для моего текущего сценария, который никогда не должен быть так.) Есть идеи?


2
2017-09-28 14:35


Источник


Добро пожаловать в SU! Мы не работаем над написанием сценариев. Что у вас есть до сих пор? Где вы застреваете? - Ƭᴇcʜιᴇ007
Извините, если я так натолкнулся. Мне удалось собрать этот фрагмент, который будет выполнять задание для одного уровня папок: «для dir in ls; do zip $ dir $ dir / *; mv $ dir * zip $ dir.cbz; done ', и мне удалось заставить его искать подпапки. В настоящее время моя самая большая проблема заключается в определении того, содержит ли папка вложенные папки или файлы. - Martin
Не беспокойся. Пожалуйста, отредактируйте свой вопрос и включите то, что у вас есть, и укажите, где / как вы застреваете, модифицируя его, чтобы делать то, что вы хотите. - Ƭᴇcʜιᴇ007


Ответы:


Другое немного другое решение:

#!/bin/bash
find toplevel/comics -type d -not -empty -print0 | while IFS= read -r -d '' dir; do
  if find "$dir" -maxdepth 1 -type f | read f; then
    zip toplevel/cbz/"$(basename "$dir").cbz" "$dir"/*
  fi
done
  • find … -print0 | while IFS= read -r -d '' file является рекомендуемая модель перебирать find Результаты. Выполнение простого find … | while read file отлично работает, но только если имена возвращенных файлов не содержат новую строку. анализ ls никогда не рекомендуется.

  • find "$dir" -maxdepth 1 -type f | read f только оценивает true, если файлы находятся в каталоге. Он достигает той же цели, что и оценка @ terdon по количеству строк, выводимых на find,

  • Котировки необходимы для всех переменных, чтобы предотвратить пропуски пробелов в именах файлов при разрыве аргументов.


4
2017-09-28 16:35



Приятный, умный в использовании read сюда. - terdon
Кажется, это прекрасно работает! Я приму ответ, как только скрипт будет выполнен, и я могу проверить один из архивов. :) - Martin


Прежде всего, никогда не разбирайте вывод ls, Кроме того, вы можете дать zip произвольное имя для создаваемого архива, поэтому вам не нужно перемещать файлы. Попробуй это:

find toplevel/comics/ -mindepth 1 -type d | 
while read dir; do 
    num=$(find "$dir" -mindepth 1 -maxdepth 1 -type f | wc -l )  
    [ "$num" -gt "0" ] && zip toplevel/cbz/"$(basename $dir)".cbd "$dir"/*; 
done

Первый find поиск команды toplevel/comics/ для каталогов (type -d), которые по меньшей мере на одном уровне ниже (-mindepth 1) заданный путь (подкаталоги). Это гарантирует, что find не вернется toplevel/comics как результат. Результаты этой находки подаются на while цикл, который обрабатывает каждый из них, сохраненный в переменной $dir, каждый $dir выполняется поиск файлов (-type f), которые на самом деле находятся в этом каталоге, а не в подкаталогах (-mindepth 1 -maxdepth 1). Количество строк, возвращаемых find (это то что wc ) сохраняется как $num и если оно больше 0, каталог будет заархивирован и архив будет помещен в cbz,

ПРИМЕЧАНИЯ: архивы будут содержать полный путь к файлам (тест путем распаковки одного из них), вы можете -j вариант zip если вы этого не хотите. Видеть man zip,


2
2017-09-28 16:28



Побей меня. Возможно, вы захотите удвоить toplevel/cbz/$(basename "$dir").cbd в случае, если базовое имя расширено пробелом. Для действительно параноидальной обработки файлов это должно быть find … -print0 | while IFS= read -r -d '' dir; do …, - slhck
@slhck хороший момент о $(basename "$dir"), ответ отредактирован. Я не включил IFS и т. Д., Чтобы все было просто, поскольку OP только начинается с сценариев оболочки, и так как у вас есть это в вашей версии. - terdon
Это выглядит очень многообещающим, но что-то еще мешает. Сделав некоторые корректировки, чтобы отразить фактическую структуру файлов, я закончил тем, что сохранил это как «cbzmaker.sh» в том, что было бы «toplevel»: #! /bin/bash find Comics -mindepth 1 -type d | while read dir; do num=$(find "$dir" -mindepth 1 -maxdepth 1 -type f | wc -l ) [ "$num" -gt "0" ] && zip CBZs/"$(basename $dir)".cbz "$dir"; done    Кажется, что он находит все папки и создает почтовые индексы на основе их имен, но все они кажутся пустыми. - Martin
@Martin извините, мое плохое, попробуйте обновленную версию. - terdon