Script Bash para converter várias seqüências de imagens em arquivos de vídeo

1

Eu estou tentando fazer um script para tirar várias séries de seqüências de imagens dentro de subdiretórios do diretório de trabalho atual e enviá-las por meio do ffmpeg para criar arquivos de vídeo no diretório de trabalho atual nomeado após os diretórios. É complicado pelo fato de os nomes das seqüências de imagens variarem, assim como o número inicial das seqüências, mas o problema real é que eu sou novo no bash scripting. Aqui está um exemplo dos arquivos:

directoryFirstRender01
     renderOne0032.png
     renderOne0033.png
     renderOne0034.png
directoryFourthRender01
     renderFour4253.png
     renderFour4254.png
     renderFour4255.png
directoryFifthRender01
     renderFiveTwo1367.png
     renderFiveTwo1368.png
     renderFiveTwo1369.png

Aqui está um esboço do script que tem vários problemas que eu conheço e provavelmente muitos mais que eu não sei. A razão pela qual eu não sei quantos problemas tem é porque fiquei preso obtendo e analisando os nomes dos arquivos, e sem isso eu não posso testar o resto:

#!/bin/bash

for DIR in (ls -d */); do
    1STFILE=(ls $dir/ | sort -n | head -1)
    STARTNO=${1STFILE:(-8):4}
    IMGSEQ=${1STFILE%????.*}
    EXTEN=${1STFILE*.}
    ffmpeg -start_number $STARTNO -i $IMGSEQ%04d.$EXTEN $DIR.mkv
done

Meus principais problemas atuais que eu conheço são:

  1. Eu não sei como obter o nome do arquivo apenas do primeiro arquivo nos diretórios. ls dir/ | sort -n | head -1 funciona no terminal, mas não em um script.
  2. A extração de substring para obter o primeiro número do primeiro arquivo só funcionaria em sequências de imagens de 4 dígitos. Existe uma maneira de aceitar renderSix00001.png-renderSix99999.png e renderSeven001.png-renderSeven999.png ? Isso também é um problema com a linha recebendo $IMGSEQ , e o %04d na linha ffmpeg precisaria ser alterado de alguma forma.
  3. Acho que vou ter problemas com a variável $IMGSEQ misturando com o %04d no nome do arquivo de entrada do ffmpeg, sem colchetes, mas ainda não cheguei tão longe. Qual sintaxe eu uso lá $IMGSEQ(%04d).$EXTEN or $IMGSEQ {%04d}.$EXTEN talvez? (Coisas como esta é porque é uma droga estar pulando no final do script)
  4. (problema menor: 1. Eu sei que usar ls em for DIR in (ls -d */) é desaprovado, mas não sei como filtrar quaisquer arquivos no diretório de trabalho atual e apenas trabalhar nos diretórios.)

Tenho certeza de que o script parece uma bagunça completa. Qualquer orientação geral para que a coisa toda funcione seria muito bem-vinda, mas se ninguém tiver paciência para me acompanhar, se eu puder obter ajuda e analisar os nomes dos arquivos, talvez eu mesmo possa consertar o resto. Obrigado.

UPDATE 1: (Depois de aplicar as sugestões de Ron)

Obrigado mais uma vez, Ron! Este é o roteiro quase final:

#!/bin/bash

for DIR in $(ls -d */)
do
    FIRSTFILE=$(ls $DIR | sort -n | head -1)
    STARTNO=$(echo $FIRSTFILE | grep -Eo "[0-9]+")
    DIGITNO=${#STARTNO} 
    IMGSEQ=${FIRSTFILE%????.*}
    EXTEN=${FIRSTFILE#*.}
    OUTPUT=${DIR%/}
    ffmpeg -start_number $STARTNO -i "$DIR$IMGSEQ"%0"$DIGITNO"d".$EXTEN" $OUTPUT.mkv
done

Como, graças a Ron, a variável $STARTNO aceitará agora comprimentos de vários dígitos, estou usando a expansão de parâmetro de comprimento na linha $DIGITNO para obter o número a ser usado na parte %04d para torná-lo %03d ou %05d , conforme necessário, para que funcionem também. Eu estou esperando que o uso liberal de " para separar o %04d das variáveis adjacentes não seja considerado uma forma ruim (se foi, qual é o caminho certo?). A única parte que falta no script (eu acho!) É como fazer com que $IMGSEQ aceite comprimentos de vários dígitos. Eu não tenho idéias para isso agora. Se alguém souber, eu gostaria de saber, mas talvez eu possa encontrá-lo vasculhando a documentação de expansão de parâmetro, como se eu não tivesse mais do que suficiente para uma vida inteira. :)

UPDATE 2: (Sucesso!)

Descobri isso! (Como fazer com que o IMGSEQ aceite nomes que envolvam comprimentos de vários dígitos) Trabalhando com base na sugestão de Ron para $STARTNO usando (echo $FIRSTFILE | grep -Eo "[0-9]+") Eu criei

IMGSEQ=$(echo ${FIRSTFILE%.*} | grep -iEo "[a-z]+")
  1. ${FIRSTFILE%.*} pega o primeiro arquivo e retira a extensão.
  2. grep é pesquisa de padrões
  3. A parte -i de -iEo é para fazer com que o grep aceite correspondências de maiúsculas e minúsculas.
  4. A parte -E de -iEo é para (citando de man grep ) "Interpretar PATTERN como uma expressão regular estendida". O que quer que isso signifique.
  5. A parte -o de -iEo é apenas imprimir o padrão correspondente.
  6. [a-z] é para corresponder ao padrão de qualquer letra do alfabeto
  7. + diz ao grep que o padrão do alfabeto anterior deve ser correspondido "uma ou mais vezes" (faça isso várias vezes para obter todas as letras).

Uma limitação disso é que ele não iria lidar com nomes de arquivos com caracteres especiais como - ou _ , mas eu posso viver com isso por enquanto.

Então aqui está o roteiro semi-final!

#!/bin/bash

for DIR in $(ls -d */)
do
    FIRSTFILE=$(ls $DIR | sort -n | head -1)
    STARTNO=$(echo $FIRSTFILE | grep -Eo "[0-9]+")
    DIGITNO=${#STARTNO} 
    IMGSEQ=$(echo ${FIRSTFILE%.*} | grep -iEo "[a-z]+")
    EXTEN=${FIRSTFILE#*.}
    OUTPUT=${DIR%/}
    ffmpeg -n -start_number $STARTNO -i "$DIR$IMGSEQ"%0"$DIGITNO"d".$EXTEN" $OUTPUT.mkv
done

Então, execute em um diretório com alguns diretórios nomeados como meus diretórios de exemplo acima (exceto que eu adicionei um com uma seqüência de imagens preenchida com mais de 4 zeros para ter certeza de que funcionou também), este script executará as seguintes linhas ffmpeg após o outro:

ffmpeg -n -start_number 0032 -i directoryFirstRender01/renderOne%04d.png directoryFirstRender01.mkv
ffmpeg -n -start_number 4253 -i directoryFourthRender01/renderFour%04d.png directoryFourthRender01.mkv
ffmpeg -n -start_number 01367 -i directoryFifthRender01/renderFiveTwo%05d.png directoryFifthRender01.mkv

Freakin 'perfeito! Muito obrigado novamente por sua ajuda Ron! Eu definitivamente não teria sido capaz de terminar sem sua ajuda.

    
por InverseTelecine 07.08.2015 / 20:41

1 resposta

1
  

Eu não sei como obter o nome do arquivo apenas do primeiro arquivo no   diretórios. ls dir / | sort -n | cabeça -1 funciona no terminal, mas   não em um script.

Você pode querer reescrever:

for DIR in (ls -d */); do
    1STFILE=(ls $dir/ | sort -n | head -1)

como

for DIR in (ls -d */)
do
    1STFILE=$(ls $DIR | sort -n | head -1)
  

Existe uma maneira de aceitar renderSix00001.png-renderSix99999.png   e renderSeven001.png-renderSeven999.png também?

Se você seguiu o acima, então:

STARTNO=$(echo STFILE | grep -Eo "[0-9]+")

deve obter todos os números no nome do arquivo.

  

Qual sintaxe eu uso lá $IMGSEQ(%04d).$EXTEN ou $IMGSEQ {%04d}.$EXTEN talvez?

Coloque essa coisa dentro de "" , então:

ffmpeg -start_number $STARTNO -i "$IMGSEQ%4d.$EXTEN" "$DIR.mkv"

Agora, se você usar apenas "$IMGSEQ%4d.$EXTEN" , vai encontrar um problema (tente ver o que é!). Então, faça isso "$DIR$IMGSEQ%4d.$EXTEN"

Se você usar "$DIR.mkv" , criará um arquivo oculto .mkv , que não é o que você deseja. Uma maneira não tão legal que pensei é armazenar apenas o nome do diretório, removendo o sufixo / em uma variável:

OUTPUT=$(echo $DIR | sed 's/\/$//')

e use isso em ffmpeg como em:

ffmpeg -start_number $STARTNO -i "$DIR$IMGSEQ%4d.$EXTEN" "$OUTPUT.mkv"
    
por Ron 08.08.2015 / 15:39