Encontre todos os arquivos de vídeo por duração

2

Eu quero mover todos os arquivos de vídeo com uma certa duração para algum diretório. Em esta resposta Eu encontrei um maneira de investigar a duração de um arquivo de vídeo:

ffprobe -i some_video -show_entries format=duration -v quiet -of csv="p=0"

Eu queria fazer algo assim com isso:

find . -test <test for duration> -exec mv {} /path/to/target ';'

No entanto, parece que find não suporta scripts arbitrários para o teste (não há -test switch). Perdi alguma coisa? Isso simplesmente não é possível com find ? Eu estou melhor apenas escrevendo um script python?

    
por user1785730 22.02.2018 / 11:25

1 resposta

3

Você pode usar -exec como seu -test . Escreva um script que aceite um argumento de nome de arquivo e sai 0 se o arquivo atender à sua condição e, caso contrário, não é zero. Eu não tenho o software FF (por exemplo, ffprobe ) no meu sistema, então eu não posso verificar isso, mas algo como

#!/bin/sh
if dur=$(ffprobe -i "$1" -show_entries format=duration -v quiet -of csv="p=0")
then
        [ "$dur" -ge 900 ]
        exit
else
        exit
fi

procuraria por um vídeo com duração ≥ 15 minutos, supondo que ffprobe produza um número inteiro de segundos. (Se relatar mm: ss ou ss.ddd, deixo as modificações triviais para você, mas veja meu exemplo abaixo para inspiração.) Explicação: o if falha se ffprobe falhar; Nesse caso, baixamos para o menor exit e saia com o status de erro de ffprobe . Se ffprobe for bem-sucedido, testamos sua saída ( "$dur" ) e saia com o resultado desse teste. Isso também poderia ser escrito

[ "$dur" -ge 900 ]  &&  exit 0  ||  exit 1

Na verdade, o script inteiro pode ser reduzido a

dur=$(ffprobe -i "$1" -show_entries format=duration -v quiet -of csv="p=0")  \
                            &&  [ "$dur" -ge 900 ]

Portanto, chame seu script de algo como check_dur ; então você pode fazer

find . -exec ./check_dur {} ';'-exec mv {} /path/to/target ';'

Isso funciona porque, como eu disse, -exec funciona como um teste, e as coisas depois de um -exec serão processadas somente se o primeiro -exec for bem-sucedido (encerrado com status 0).

Como eu disse Eu não tenho o software FF (por exemplo, ffprobe ) no meu sistema, então testei com esse script:

#!/bin/sh
if mod=$(stat -c%y "$1")
then
        mod=${mod#*-}
        mod=${mod%%-*}
        mod=${mod#0}
        [ $(( mod%2 )) = 0 ]
        exit
else
        exit
fi

que testa se a data de modificação de um arquivo ou diretório está em um mês com numeração par. Nota: no meu sistema (en_US), stat -c%y filename produz a data de modificação no formato yyyy-mm-dd HH:MM:SS.ddddddddd -(TZ) . Então, o código acima

  1. retira o ano (da esquerda),
  2. retira tudo depois do mês e
  3. retira um 0 , se houver (porque $((…)) interpreta um zero à esquerda como um indicador de que um número é octal, e, portanto, relata um erro para 08 e 09 ).

Algumas outras notas:

  1. Para mv , o comando pode ser melhorado um pouco alterando-o para

    find . -exec ./check_dur {} ';' -exec mv -t /path/to/target {} +
    

    que executará mv uma vez com muitos arquivos. Você não pode fazer isso com o primeiro -exec , porque -exec ... + não pode ser usado como um teste.

  2. Se você não quiser escrever um script separado, você pode usar sh -c e inline o script; por exemplo,

    find . -exec sh -c 'dur=$(ffprobe -i "$1" -show_entries format=duration -v quiet -of csv="p=0") && [ "$dur" -ge 900 ]' sh {} ';'-exec mv -t /path/to/target {} +
    

    Isso cria um mini-script de uma linha (a string após o sh -c ) e passa o nome do arquivo ( {} ) para ele como um argumento. Algumas versões do find vai deixar você incorporar o {} no mini-script, mas esta é uma má ideia:

    • Não funciona para todas as versões de find e
    • mesmo quando funciona, em geral ele falhará (e talvez até falhe catastroficamente) em alguns nomes de arquivos.
por 23.02.2018 / 07:03