Arquivos zip recursivamente em arquivos .cbz baseados na pasta na linha de comando

2

Estou tentando descobrir como escrever um script para automatizar a criação de arquivos .cbz a partir de imagens em pastas no OSX.

Minha árvore de diretórios será assim:

/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

E o que eu gostaria de fazer é executar um script que encontrará qualquer pasta contendo arquivos reais em vez de subpastas e compactá-lo, renomeá-lo de .zip para .cbz e mover o arquivo .cbz para a pasta / cbz em o nível superior. Qualquer pasta que contenha subpastas não deve conter arquivos, o que pode ser útil. Também não espero que haja subpastas mais profundas do que as mostradas no exemplo acima.

Onde estou: Este trecho irá procurar por uma pasta e criar os arquivos .cbz para cada subpasta.

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

Eu também encontrei alguns trechos que farão algo semelhante a cada subpasta abaixo da pasta selecionada, mas eu tive resultados variados e estaria muito interessado em aprender a melhor maneira de executar uma operação somente em pastas. Também não tenho idéia de como devo verificar se uma determinada pasta contém subpastas ou arquivos. (Eu acho que idealmente eu deveria incluir cheques para ver se há ambos, mas para o meu cenário atual que nunca deveria ser o caso.) Alguma idéia?

    
por Martin 28.09.2013 / 16:35

2 respostas

4

Outra solução ligeiramente diferente:

#!/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 é um padrão recomendado para iterar mais de find dos resultados. Fazer um find … | while read file simples funciona bem, mas apenas se os nomes dos arquivos retornados não contiverem uma nova linha. Parsing ls nunca é recomendado.

  • find "$dir" -maxdepth 1 -type f | read f só avalia true se forem encontrados arquivos no diretório. Ele atinge o mesmo objetivo da avaliação do @ terdon sobre o número de linhas geradas por find .

  • As cotações são necessárias em torno de todas as variáveis para evitar que os espaços em branco nos nomes dos arquivos quebrem os argumentos.

por 28.09.2013 / 18:35
2

Primeiro de tudo, nunca analisa a saída de ls . Além disso, você pode dar a zip um nome arbitrário para o arquivo que ele irá criar, para que você não precise mover os arquivos. Tente isto:

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

O comando 1st find pesquisa toplevel/comics/ para diretórios ( type -d ) que estão pelo menos um nível abaixo ( -mindepth 1 ) do caminho fornecido (subdiretórios). Isso garante que find não retornará toplevel/comics como resultado. Os resultados desse achado são canalizados para o loop while , que processa cada um deles salvo na variável $dir . Cada $dir é pesquisado por arquivos ( -type f ) que estão realmente nesse diretório e não em subdiretórios ( -mindepth 1 -maxdepth 1 ). O número de linhas retornadas pelo find (que é o wc ) é salvo como $num e, se for maior que 0, o diretório é compactado e o arquivo colocado em cbz .

NOTAS: Os arquivos conterão o caminho completo para os arquivos (teste descompactando um), você pode querer dar a opção -j para zip se você não quiser isto. Consulte man zip .

    
por 28.09.2013 / 18:28