2

Я хочу переместить все видеофайлы с определенной продолжительностью в какой-либо каталог.  В этом ответе я нашел способ проверить продолжительность видеофайла:

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

Я хотел сделать что-то подобное с этим:

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

Однако, похоже, что find не поддерживает произвольные сценарии для теста (переключатель -test отсутствует). Я что-то пропустил? Это просто невозможно find? Мне лучше просто написать скрипт на Python?

1 ответ1

3

Вы можете использовать -exec как -test . Напишите скрипт, который принимает один аргумент имени файла и выходит из 0, если файл соответствует вашему условию, и ненулевой в противном случае.  У меня нет программного обеспечения FF (например, ffprobe) в моей системе, поэтому я не могу проверить это, но что-то вроде

#!/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

будет проверять видео продолжительностью ≥ 15 минут, предполагая, что ffprobe выдает целое число секунд.  (Если он сообщает mm:ss или ss.ddd, я оставляю тривиальные модификации для вас, но для вдохновения см. Мой пример ниже.)  Объяснение: сбой if if сбой ffprobe ; в этом случае мы переходим к нижнему exit и выходим со статусом ошибки из ffprobe .  Если ffprobe успешно выполняется , мы проверяем его вывод ("$dur") и затем завершаем работу с результатом этого теста. Это также может быть написано

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

На самом деле весь сценарий действительно может быть уменьшен до

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

Поэтому назовите ваш скрипт как-то так: check_dur ; тогда вы можете сделать

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

Это работает, потому что, как я уже сказал, -exec работает как тест, и все, что после -exec будет обрабатываться, только если первый -exec успешно (выход со статусом 0).

Как я уже сказал, в моей системе нет программного обеспечения FF (например, ffprobe), поэтому я протестировал этот скрипт:

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

который проверяет, находится ли дата изменения файла или каталога в четном месяце.  Примечание: в моей (en_US) системе stat -c%y filename выводит дату модификации в формате yyyy-mm-dd HH:MM:SS.ddddddddd -(TZ) .  Итак, приведенный выше код

  1. снимает год (слева),
  2. снимает все после месяца, и
  3. удаляет начальный 0 , если он есть (потому что $((…)) интерпретирует начальный ноль как показатель восьмеричного числа, и поэтому он сообщает об ошибке для 08 и 09).

Пара других заметок:

  1. Для mv команду можно немного улучшить, изменив ее на

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

    который выполнит mv один раз со многими файлами.  Вы не можете сделать это с первым -exec , потому что -exec ... + не может использоваться в качестве теста. 

  2. Если вы не хотите писать отдельный скрипт, вы можете использовать sh -c и встроить скрипт; например,

    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 {} +
    

    Это создает однострочный мини-скрипт (строка после sh -c) и передает ему имя файла ({}) в качестве аргумента.  Некоторые версии find позволяют включать {} в мини-скрипт, но это плохая идея:

    • Это не работает для всех версий find , и
    • даже когда он работает, в общем случае он потерпит неудачу (и может даже потерпеть неудачу) для некоторых имен файлов.

Всё ещё ищете ответ? Посмотрите другие вопросы с метками .