Solucionado (ver solução)
Solucionado
(ver solução)
6
respostas

Um Shell Script que verifica se uma imagem já foi convertida ou pasta esta vazia

Fiquei pensando em um código que:

  • Quando a pasta estiver vazia ele converte os arquivos todos
  • Quando há um arquivo convertido e um arquivo com o mesmo nome do arquivo que será convetido ele ignora e converte os arquivos que estão faltando
# !/bin/bash


    PATH0FILE=~/ShellScript/Convertidos
    PATH1FILE=~/ShellScript/Imagens
    FC=0
    FD=0
    file0_convert(){
        cd $1
        for FILE0 in *.png ; do
            if [ -a $FILE0 ] ; then    
            echo "teste"
            local NO_EXTENSION=$(ls $FILE0 -1 | awk -F . '{ print $1 }')
            echo $NO_EXTENSION
            file1_convert $NO_EXTENSION $PATH1FILE
            cd $1        
            continue    
            else
            echo "Pasta está vazia"    
            file1_convert "Sem conversão" $PATH1FILE
            fi        
        done
    }

    file1_convert(){
        cd $2
        for FILE1 in *.jpg ; do
            local NO_EXTENSION=$(ls $FILE1 -1 | awk -F . '{ print $1 }')
            if [ $NO_EXTENSION = "$1" ] ; then    
            echo "Arquivo ja convertido $1"
            let FD++        
            break #Eu coloquei o break aqui para fazer um teste     
            else
            convert $NO_EXTENSION.jpg $NO_EXTENSION.png
            mv *.png $PATH0FILE
            echo "Criando imagens"
            let FC++            
            fi        
        done


    }

file0_convert $PATH0FILE
echo "Arquivos Existentes:$FD"
echo "Arquivos convertidos:$FC"

O que o codigo está fazendo com o break:

  • Se a primeira estiver na pasta das imagem convertidas que no caso se chama Cachorro.png. Sendo, ela estando somente no diretório, fazendo parar a execução.
  • Se a ultima imagem estiver na pasta das imagens convertidas que no caso é Sol.png. Sendo, ela estando somente no diretório, fazendo converter todas até chegar nela mesma parando a execução.
  • Se alguma imagem que está entre a primeira e a ultima na pasta das imagens convertidas. Sendo, alguma delas estando somente no diretório, fazendo converter todas até chegar nela mesma parando a execução do codigo.

Motivos:

Quando chega no if da função file1_convert() é verificado se tem nomes iguais. Se houver nomes iguais a execução para naquele ponto. Ou seja, se a ultima imagem estiver somente na pasta, vai se coverter as imagens até chegar nela mesma.

if [ $NO_EXTENSION = "$1" ] ; then

Conclusão:

Não é eficiente para converter as imagens restantes, se caso a primeira ou alguma outra imagem menos se a ultima imagem estiver na pasta. Isso faz com que a execução seja interrompida não completando a tarefa. E a execução do codigo é pouco demorada, podemos perceber, pela quantidade de vezes que passou pela conver(sç -> Escolha a opção correta )ão Arquivos convertidos:91

O que está abaixo demonstra como o codigo se comporta se todas as imagens estiverem na pasta. O total de imagens é 14

teste
Cachorro
Arquivo ja convertido Cachorro
teste
Cratera
Criando imagens
Arquivo ja convertido Cratera
teste
Dados
Criando imagens
Criando imagens
Arquivo ja convertido Dados
teste
DesenhoHomer
Criando imagens
Criando imagens
Criando imagens
Arquivo ja convertido DesenhoHomer
teste
DesenhoSimpsons
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Arquivo ja convertido DesenhoSimpsons
teste
flor
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Arquivo ja convertido flor
teste
Gato
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Arquivo ja convertido Gato
teste
Girasol
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Arquivo ja convertido Girasol
teste
Lago
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Arquivo ja convertido Lago
teste
Linux
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Arquivo ja convertido Linux
teste
Lobo
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Arquivo ja convertido Lobo
teste
Montanha
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Arquivo ja convertido Montanha
teste
Planta
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Arquivo ja convertido Planta
teste
Sol
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Arquivo ja convertido Sol
Arquivos Existentes:14
Arquivos convertidos:91

CONTINUAÇÃO EM BAIXO

6 respostas

CONTINUAÇÂO...

O que o codigo está fazendo sem o break:

-Se tiver alguma imagem que começa com a primeira ou com a ultima na pasta das imagens convertidas não importando qual seja. Sendo, elas estando somente no diretório, fazendo converter todas parando a execução do codigo na ultima imagem.

Motivos:

Quando chega no if da função file1_convert() é verificado se tem nomes iguais. Se houver nomes iguais a execução não para naquele ponto. Ou seja, não importando qual imagem estiver somente na pasta, vai se coverter todas imagens até chegar na ultima.

if [ $NO_EXTENSION = "$1" ] ; then

Conclusão:

É eficiente para converter as imagens restantes, não importando qual imagem estiver na pasta. Isso não faz com que a execução seja interrompida completando a tarefa.

E a execução do codigo é muito demorada, podemos perceber, pela quantidade de vezes que passou pela converção Arquivos convertidos:182.

#Repetição omitda#
Nome da imagem
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
Criando imagens
#Repetição omitida#
Arquivo ja convertido Nome da imagem
Arquivos Existentes:14
Arquivos convertidos:182

Minha questão é , como eu faço para que eu consiga converter todas as imagens restantes, não importando qual imagem estiver na pasta já convertida, evitando que varias conversões sejam feitas?

O principal ponto é somente converter as imagens que precisam ser convertidas que já não existe na pastas das convertidas.

Não me pergunte como eu fiz esse código. Mas acho que foi algo assim....

Bom dia, soterdholston!

Legal, realmente está um pouco caótico o código e vou poder ajudar bastante. Primeiro, vamos resolver os seus bugs.

Olhe este pseudo código:

funcao converte (nome):
    para cada nomeDeImagem na pasta de convertidas:
        se o nome for igual ao nomeDeImagem: para a execução
        converte nome.jpg para nome.png
        move imagem para pasta de convertidas

Identifiquei dois bugs que são solucionáveis da mesma maneira:

  1. Se não houver nenhuma imagem na pasta de convertidas, você não faz nada, pois toda a sua lógica está dentro do loop. Ou seja, se tiver a seguinte estrutura:
     + Imagens/
         - cachorro.jpg
         - gato.jpg
         - furao.jpg
     + Convertidas/
    O que vai acontecer é que a lógica nem entra no loop e não converte nada. Para corrigir isso, seria bom trocar o break por um return para sair completamente do método, e jogar a conversão para fora do loop.
     funcao converte (nome):
         para cada nomeDeImagem na pasta de convertidas:
             se o nome for igual ao nomeDeImagem: sai do método
         converte nome.jpg para nome.png
         move imagem para pasta de convertidas
  2. Sempre que você encontrar uma imagem que não tiver um nome igual à imagem que quer converter, você faz a conversão. Ou seja, se tiver a seguinte estrutura:
     + Imagens/
         - cachorro.jpg
         - gato.jpg
         - furao.jpg
     + Convertidas/
         - macaco.png
         - cobra.png
         - mangusto.png
    O que vai acontecer é que a imagem cachorro.jpg vai ser convertida 3 vezes. Depois a imagem gato.jpg vai ser convertida 4 e a furao.jpg será convertida 5 vezes. Ok, isso não é um problema. Só torna o programa mais lento. A solução do bug 1 resolve o bug 2 também.

Legal, mas o programa ainda está meio confuso, cheio de loops, não é? Vamos melhorá-lo. Isso fica pro próximo post, já que esse aqui já resolve o seu problema.

Ps.: O código corrigido do método file1_convert:

file1_convert() {
    cd $2
    for FILE1 in *.jpg ; do
        local NO_EXTENSION=$(ls $FILE1 -1 | awk -F . '{ print $1 }')
        if [ $NO_EXTENSION = "$1" ] ; then
            echo "Arquivo ja convertido $1"
            let FD++
            return 0
        fi
    done
    convert $NO_EXTENSION.jpg $NO_EXTENSION.png
    mv *.png $PATH0FILE
    echo "Criando imagens"
    let FC++
}

Agora vamos dar uma otimizadas marotas nesse script aí, pode ser? Se ficar com dúvida sobre algo, pode perguntar à vontade hein, pode ser que eu me empolgue pois gosto bastante de bash!

Só pra formalizar, o objetivo do programa é:

  1. Ler todos os arquivos de uma pasta
  2. Para cada arquivo, olhar outra pasta e conferir se já existe uma conversão desse arquivo, de jpg pra png.
  3. Caso exista, pular o arquivo.
  4. Caso não exista, converter o arquivo.
  5. Retornar o número de arquivos convertidos e arquivos que já existiam.

Então vamos fazer a estrutura de métodos que vai fazer essa lógica funcionar:


function arquivoExiste() {
    echo "false"
}

function converteArquivo() {
    echo "Arquivo convertido!"
}

function converteTodos() {
}

EXISTENTES=0
CONVERTIDOS=0

# converte tudo
converteTodos

echo "Arquivos existentes : ${EXISTENTES}"
echo "Arquivos convertidos: ${CONVERTIDOS}"

Legal, o código acima por hora só imprime algumas saídas de exemplo sobre o número de arquivos convertidos e existentes. Vamos implementar a lógica de conversão de todos os arquivos do diretório.


# outras funções ...

function converteTodos() {
    # cria, se necessário, a pasta de arquivos convertidos
    mkdir -p "${CONVERTIDOS_DIR}"

    # para cada arquivo com extensão .jpg, chama o método converteArquivo
    for file in *.jpg; do
        converteArquivo "${file}"
    done
}

EXISTENTES=0
CONVERTIDOS=0
CONVERTIDOS_DIR="Convertidos"

# entra no diretório alvo
pushd "$@"

# converte tudo
converteTodos

# sai do diretório alvo
popd

echo "Arquivos existentes : ${EXISTENTES}"
echo "Arquivos convertidos: ${CONVERTIDOS}"

Agora que entramos no diretório alvo, criamos o diretório de conversão e estamos chamando o método de conversão de arquivo, temos uma saída diferente: um "Arquivo convertido!" para cada arquivo a ser convertido.

Agora vamos implementar a lógica de conversão de um arquivo, independente do retorno que temos sobre ele existir ou não. Inicialmente, todos os arquivos serão convertidos.

function converteArquivo() {
    # armazena o nome completo do arquivo
    local arquivo="${1}"

    # armazena o nome do arquivo sem a extensão
    # ${var%PATTERN} -> remove a primeira ocorrência de PATTERN do **final** do conteúdo da variável var
    # no caso, ".*" remove tudo o último ponto encontrado no arquivo e tudo que vier a seguir. exemplo: cat.dog.bird => cat.dog
    local arquivoSemExt="${arquivo%.*}"

    # confere se arquivo existe chamando o método arquivoExsite e conferindo se o retorno em texto dele é "true"
    # por hora sempre é "false"
    if [ "$(arquivoExiste $arquivoSemExt)" = "true" ]; then
        # soma 1 na contagem de arquivos existentes
        let EXISTENTES++
        return 0
    fi
    # chama o método convert que faz a conversão.
    convert "${arquivo}" "${CONVERTIDOS_DIR}/${arquivoSemExt}.png"

    # soma 1 na contagem de arquivos convertidos
    let CONVERTIDOS++
    echo "Arquivo convertido para '${arquivoSemExt}.png'!"
}

Opa, sucesso. Todos os nossos arquivos estão sendo convertidos para a pasta local Convertidos. Agora falta implementar se o arquivo existe ou não:

function arquivoExiste() {
    # utilizamos aqui o $@ pois é o conjunto de todos os parâmetros.
    # caso haja espaços no nome do arquivo, isso garante que o nome completo será armazenado
    local arquivoSemExt="$@"

    # -f confere se existe um arquivo neste caminho com este nome    
    if [ -f "${CONVERTIDOS_DIR}/${arquivoSemExt}.png" ]; then
        echo "true"
    else
        echo "false"
    fi
}

Uma variação inline pra esse método seria:

function arquivoExiste() {
    local arquivoSemExt="$@"
    [ -f "${CONVERTIDOS_DIR}/${arquivoSemExt}.png" ] && echo "true" || echo "false"
}

Bacana! Agora está tudo funcionando! No post seguinte vou postar só o código final.

Últimos detalhes: É bom redirecionar a saída do pushd e popd para não sujar o seu log, então podemos alterar:

pushd "$@" > /dev/null
popd > /dev/null
solução!

E aqui vai a versão final, completa!

#!/bin/bash

function arquivoExiste() {
    local arquivoSemExt="$@"
    [ -f "${CONVERTIDOS_DIR}/${arquivoSemExt}.png" ] && echo "true" || echo "false"
}

function converteArquivo() {
    local arquivo="${1}"
    local arquivoSemExt="${arquivo%.*}"
    if [ "$(arquivoExiste $arquivoSemExt)" = "true" ]; then
        let EXISTENTES++
        return 0
    fi
    convert "${arquivo}" "${CONVERTIDOS_DIR}/${arquivoSemExt}.png"
    let CONVERTIDOS++
    echo "Arquivo convertido para '${arquivoSemExt}.png'!"
}

function converteTodos() {
    mkdir -p "${CONVERTIDOS_DIR}"

    for file in *.jpg; do
        converteArquivo "${file}"
    done
}

EXISTENTES=0
CONVERTIDOS=0
CONVERTIDOS_DIR="Convertidos"

pushd "$@" > /dev/null
converteTodos
popd > /dev/null

echo "Arquivos existentes : ${EXISTENTES}"
echo "Arquivos convertidos: ${CONVERTIDOS}"

Espero ter ajudado e qualquer dúvida, pode perguntar! Um abração e bons estudos!

Muito obrigado, cara!

Sua ajuda é muito útil para alguém como, eu, que não sabe nada. Mas o que vale é tentar, né? (Confesso que não sei nada da estrutura bash. Estou metendo o loko..... hehehe XD)

Comentário de marco-salles :


Identifiquei dois bugs que são solucionáveis da mesma maneira:

Se não houver nenhuma imagem na pasta de convertidas, você não faz nada, pois toda a sua lógica está dentro do loop. Ou seja, se tiver a seguinte estrutura:

  • Imagens/

    • cachorro.jpg
    • gato.jpg
    • furao.jpg
  • Convertidas/

Na função abaixo eu mando varrer a pasta convertidas com o código

 file0_convert(){
        cd $1 # Entro na pasta da imagens convertidas
        for FILE0 in *.png ; do  # faço uma varredura na pasta 
            if [ -a $FILE0 ] ; then  # se existe algum arquivo  
        #Codigo omitido#
            else  #Se não tiver nem um arquivo 
            echo "Pasta está vazia"    
            file1_convert "Sem conversão" $PATH1FILE 
                #Vai para a pasta onde está as imagens
                # Converta todas elas e mova todas elas 
                # para a pasta convertidas   
            fi

Acreditei que esse codigo já resolvia o meu problema com a pasta. Se não houvesse nenhuma imagem na pasta das convertidas, eu iria direto para a pasta não convertidas, convertendo tudo, movendo para a pasta convertidas. Estando toda a lógica dentro do loop a pasta seria varrida, assim, eu saberia se existe algum arquivo .png existente lá dentro ou não.

Resumindo, os problemas:

  • Olha pasta das convertidas -> OK
  • Se houver arquivos .png lá dentro -> OK
    • Memoriza quais arquivos já foram convertidos -> Sem Sucesso
    • Avisa que já foram convertidos -> OK
    • Envia o nome de cada arquivo convertido para serem comparados com os arquivos originais -> Sem sucesso
  • Se não há arquivos .png na pasta -> OK
    • Converte tudo da pasta das imagens não convertidas -> OK

Eu parti desta lógica, para que , primeiro, verifique quais arquivos eu já tenho iguais do original ou se a pasta está vazia. Segundo, ter essa relação de arquivos que por algum motivo foram já convertidos.

-----------------Vamos abstrair um pouco-------------------

Pensa assim a pasta das imagens originais é um SPOOL. Um script de limpeza, que apaga todos os arquivos desse SPOOL, foi interrompido. Com script de limpeza parado foram adicionadas novas imagens, ou seja, há as imagens antigas + imagens novas. Todas as imagens antigas já foram convertidas.

Agora o script de converção foi escalonado. Seu trabalho é checar a pasta das imagens convertidas, depois, verificar os arquivos que são iguais e ignorá-los, convertendo os arquivos divergentes.

------------------------------------Fim--------------------------

Foi assim que eu pensei :/

Demorou séculos para eu entender o seu código mas no fim deu tudo certo :D

Bom dia, Paulo! Lendo sua resposta reparei que realmente eu li seu código e interpretei errado. Provavelmente devido aos nomes de método e variável pouco explicativos, já dou a dica pra deixar um pouco mais claro pra que serve cada coisa.

Como eu disse, me empolguei e acabei fazendo algumas mudanças, como por exemplo o diretório de convertidas estar dentro do diretório para conversão. Aliás, daria até pra fazer uma chamada recursiva no diretório de conversão, hein? Que tal o desafio? Haha

Bom, entendi sim o seu problema e propósito do script agora, e basicamente a diferença seria tirar a criação do diretório das imagens convertidas e deixar esse endereço estático.

Desculpe também se ficou confuso. Deixei tudo passo a passo e bem comentado pra tentar reduzir bastante essa confusão, mas parece que não foi o bastante. No final você conseguiu identificar os probemas no seu próprio código pra resolvê-los, ou acabou só dando ctrl+c/v no que eu postei e adaptando pro seu caso de uso? Acho que seria bom pro aprendizado fazer essa correção.

Outra coisa: não tinha entendido que era necessário armazenar os nomes das imagens que já haviam sido convertidas, mas isso seria fácil de fazer usando algum arquivo temporário que depois pode ser lido. Veja comentários 1. e 2. e diga o que acha das mudanças abaixo.

function converteArquivo() {
    local arquivo="${1}"
    local arquivoSemExt="${arquivo%.*}"
    if [ "$(arquivoExiste $arquivoSemExt)" = "true" ]; then
        let EXISTENTES++
        echo "${arquivoSemExt}" >> temp.txt # 1. adicionar essa linha aqui
        return 0
    fi
    convert "${arquivo}" "${CONVERTIDOS_DIR}/${arquivoSemExt}.png"
    let CONVERTIDOS++
    echo "Arquivo convertido para '${arquivoSemExt}.png'!"
}
echo -n "" > temp.txt # 2. adicionar no começo do script inteiro pra limpar o arquivo temporário

Bom, sei que o tópico foi resolvido, mas se quiser mais ajuda nesse quesito, se quiser uma explicação mais detalhada ou tentar fazer a adaptação do seu código, pode mandar bala aqui mesmo.

Um abraço e bons estudos!