LINUX.ORG.RU

bash и экранизация «ужаса»

 ,


0

2

Мне необходимо обработать огромное кол-во видеофайлов создав превьюшки к каждому из них. Написал вот такой скриптец:

#!/bin/sh

VIDEO_PATH="/var/www/wp-content/uploads"
PREVIEW_PATH="/var/www/wp-content/uploads/preview"
SIZE="250x250"
SEC=10

for X in `find $VIDEO_PATH/* -name "*.mp4"`; do
        FILENAME="${X}" #`basename $X .mp4`
        if [ ! -f $PREVIEW_PATH/"${FILENAME}".png ]; then
                ffmpeg -i "${X}" -vframes 1 -an -s $SIZE -ss $SEC $PREVIEW_PATH/"${FILENAME}".png
        fi
done

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

Покер: no such file or directory

часть: no such file or directory

/var/www/wp-content/uploads//FreeVods_update_03_2012/Tourney/JonathanLittle: no such file or directory

Ну а последнее имя файла - JonathanLittle @ Контроль банка в МТТ Покер видео.mp4.

Жду любых замечаний и предложений.

★★★★★

`find $VIDEO_PATH/* -name «*.mp4»`

Может в этом месте разбивает?

ziemin ★★
()

for X in `find..

find .. | while read -r file; do ..  — все же пробелы в именах вероятны

// ps

/var/www/wp-content/uploads/

повторяется же

FILENAME=«${X}» #`basename $X .mp4`

И нахера это? если осталось от старых правок - то зачем сюда постить?

$PREVIEW_PATH/"

Ну и занести в кавычки: мало ли переменная обзаведется пробелом.

anonymous
()
Ответ на: комментарий от anonymous

Давай, например.

Питон был вброшен раньше, жду пример.

// Если будет акцент на том, что скрипт должен обрабатывает _любые_ допустимые файлы, оставлю за собой право на башизмы).

anonymous
()

Потому что массив в баше интерпретирует " " как окончание строки. Можно например «дёргать» IFS-переменную в скрипте.

hope13 ★★★
()

экранизация «ужаса»

Я думал в треде будет про Лавкрафта и голливудских трешоклепателей

panfutij
()
Ответ на: комментарий от hope13

Потому что массив в баше интерпретирует " " как окончание строки.

Эм.. а где здесь _массив_?

anonymous
()
touch 'hello $ world @ .mp4'
touch abc.mp4
find -name '*.mp4' -print0 | while read -rd $'\0' file
do
  base="$(basename "$file" .mp4)"
  touch "$base".png
done

См. также xargs -0

gv
()
Ответ на: комментарий от panfutij

экранизация «ужаса»

Я думал в треде будет про Лавкрафта и голливудских трешоклепателей

Неэкранированный символ доллара плотно обнял шупальцами бедного Альфреда, все сильнее и сильнее сжимая его грудь. Казалось, что высвободиться из тугих пут разъяренного древнего создания невозможно, как вдруг из пучин поднялось нечто, что заставило содрогнуться даже чудище: над вспенившейся водой, сверкая острыми как лезвие бритвы концами туловища, появился огромный обратный слэш. Неэкранированный символ доллара в ужасе отпрянул в сторону: непреодолимый животный страх перед более сильным и могущественным существом заставил его отойти.

Воспользовавшись секундной передышкой, Альфред вскочил на ноги и побежал прочь от глубинный созданий, невесть для чего пробудившихся и поднявшихся с глубин. Он не мог постить на лор даже тупняк: его разум сковало непреодолимое чувство ужаса...

bk_ ★★
()

В принципе есть 2 варианта - либо менять переменную IFS либо пользоваться read, - что предпочтительнее. Например так:


find "$VIDEO_PATH" \( -name "*.mp4" \) -print | while read FILE
do
#тут дейстивия с $FILE
done

hope13 ★★★
()
Ответ на: комментарий от gv

Вот только ошибку выдало вот тут:

[mov,mp4,m4a,3gp,3g2,mj2 @ 0x16a1480]moov atom not found
/var/www/wp-content/uploads/FreeVods_update_03_2012_/Holdem/Shizofrennik @ live-session 5_10$ Покер видео.mp4: Error while opening file

Может я где накосячил?

#!/bin/sh

VIDEO_PATH='/var/www/vods4/wp-content/uploads'
PREVIEW_PATH='/var/www/vods4/wp-content/uploads/preview'
SIZE="250x250"
SEC=10

find $VIDEO_PATH/* -name '*.mp4' -print0 | while read -rd $'\0' file
do
  base="$(basename "$file" .mp4)"
  ffmpeg -i "${file}" -vframes 1 -an -s $SIZE -ss $SEC $PREVIEW_PATH/"${base}".png
done
soko1 ★★★★★
() автор топика
Ответ на: комментарий от snoopcat

Спасибо, попробую и это на всякий случай. Не слышал ранее про этот разделитель

soko1 ★★★★★
() автор топика
find $VIDEO_PATH/* -name "*.mp4" -exec bash -c "[ -f \"$PREVIEW_PATH/{}\".png ] || ffmpeg -i \"{}\" -vframes 1 -an -s $SIZE -ss $SEC $PREVIEW_PATH/\"{}\".png"

надо попробовать так ) а вообще, то, что в параметрах к exec, я бы вынес в отдельный скрипт.

//тред не читал

upd: да, с print0 тоже хороший вариант

aol ★★★★★
()
Последнее исправление: aol (всего исправлений: 1)
Ответ на: комментарий от anonymous
#!/usr/bin/python3
import glob,os,os.path

video_path='/var/www/wp-content/uploads/'
preview_path='/var/www/wp-content/uploads/preview/'
size='250x250'
sec='10'

os.chdir(video_path)

for video in glob.iglob('*.mp4'):
  thumbnail=os.path.join(preview_path,video+'.png')

  if not os.path.exists(thumbnail):
    os.system('ffmpeg -i '+video+' -vframes 1 -an -s '+size+' -ss '+sec+' '+thumbnail)
anonymous
()

Для отладки bash скриптов используются:

1) замена «команда» на «echo команда»

2) трассировка. Нужно добавить «set -x» ближе к началу файла

router ★★★★★
()
Ответ на: комментарий от anonymous

Если не нужно двойное расширение:

-thumbnail=os.path.join(preview_path,video+'.png')
+thumbnail=os.path.join(preview_path,video[:-4]+'.png')

anonymous
()

for p in ${VIDEO_PATH}/*.mp4; do ...

баш сам умеет разыменовывать звёздочки.

anonymous
()
Ответ на: комментарий от anonymous

Круто, но есть два НО :)

1)

TaN: no such file or directory
(имя «файла 2013 FreeVods_update_03_2012 FreeVods_update_03_2012_ preview TaN _ LuckyLake @ разбор раздач, 8-я часть Покер видео.mp4»)
2) искать нужно рекурсивно, а не только в каталоге /var/www/wp-content/uploads/

soko1 ★★★★★
() автор топика
Ответ на: комментарий от soko1

Да, тупанул.

#!/usr/bin/python3
import os,os.path,subprocess

video_path='/var/www/wp-content/uploads/'
preview_path='/var/www/wp-content/uploads/preview/'
size='250x250'
sec='10'

os.chdir(video_path)

for subdirectory,_,videos in os.walk('.'):
  for video in videos:
    thumbnail=os.path.join(preview_path,video[:-3]+'png')

    if video.endswith('.mp4')and not os.path.exists(thumbnail):

      subprocess.call(('ffmpeg','-i',os.path.join(subdirectory,video),
        '-vframes','1','-an','-s',size,'-ss',sec,thumbnail))

anonymous
()
Ответ на: комментарий от soko1

искать нужно рекурсивно, а не только в каталоге /var/www/wp-content/uploads/

globstar If set, the pattern ** used in a pathname expansion context will match all files and zero or more directories and sub- directories. If the pattern is followed by a /, only directories and subdirectories match.

drBatty ★★
()
Ответ на: комментарий от soko1

Может я где накосячил?

Не вижу. Может проблема уже в ffmpeg? Попробуйте переименовать файл, вызывать ffmpeg и переименовать обратно.

gv
()

ктож так делает?? ППЦ

$ find ../v -type f | while read f; do echo "file: '$f'"; bf=$(basename "$f"); echo "basename: '$bf'"; if [ ! -f "$bf" ]; then echo "not found"; touch "$bf"; else echo "found"; fi; done
file: '../v/1 @ * 20281$ 2 3'
basename: '1 @ * 20281$ 2 3'
not found
file: '../v/1 2 3'
basename: '1 2 3'
not found
file: '../v/1 @ * 2 3'
basename: '1 @ * 2 3'
not found
$ find ../v -type f | while read f; do echo "file: '$f'"; bf=$(basename "$f"); echo "basename: '$bf'"; if [ ! -f "$bf" ]; then echo "not found"; touch "$bf"; else echo "found"; fi; done
file: '../v/1 @ * 20281$ 2 3'
basename: '1 @ * 20281$ 2 3'
found
file: '../v/1 2 3'
basename: '1 2 3'
found
file: '../v/1 @ * 2 3'
basename: '1 @ * 2 3'
found

что может быть проще??

будет работать, если в именах файлов нет переводов строк. Если есть, то юзайте read -d'\0'

drBatty ★★
()
Ответ на: комментарий от anonymous

Изумительно :) Спасибо огромное. Пожалуй пример с питоном и буду использовать!

soko1 ★★★★★
() автор топика
Ответ на: комментарий от gv

Позже как будет время поэкспериментирую и отпишусь, пока что приведённый на питоне скрипт юзану

soko1 ★★★★★
() автор топика

А кто в курсе как на похапэ побороть проблему с '$' в именах файлов? А то цмска на вордпресе и я только сейчас заметил что файлы в базу кладутся без этого символа :(

soko1 ★★★★★
() автор топика
Ответ на: комментарий от anonymous

for video in glob.iglob('*.mp4')

Не-а, это обход самого острого места: в shell тоже можно for ... in *.mp4.

os.system('ffmpeg -i '+...)

Уже не очень смотрится.

anonymous
()
Ответ на: комментарий от anonymous

+thumbnail=os.path.join(preview_path,video[:-4]+'.png')

Замечаем, что остались *.mpeg -> чуть меняем скрипт -> ??? -> non profit. splitext отменили?

anonymous
()
Ответ на: комментарий от soko1

base=«$(basename »$file" .mp4)"

gv превратно «осилил» твой «коммент» (basename). расширение отбрасывается так: ${file%.*} (можно сразу вместо «${base}».png).

anonymous
()
Ответ на: комментарий от anonymous

А, пардон, там скорее всего линк (или что-нибудь в этом духе): можно добавить в find: -type f

anonymous
()

И никаких гвоздей.

find $VIDEO_PATH -name '*.mp4' -print0 | xargs -0 -L1 -I{} ffmpeg -i {} -vframes 1 -an -s $SIZE -ss $SEC $PREVIEW_PATH/{}.png

anonymous
()
Ответ на: комментарий от ttnl

А могли бы переписать это на Си? Интересно было бы посмотреть :) Ну это так, если не в лом. Там наверное без system() тоже ведь не обойтись?

soko1 ★★★★★
() автор топика
Ответ на: комментарий от anonymous

ОК, только вряд ли ошибку выдает basename.

gv
()
Ответ на: комментарий от ttnl

Я кстати потому и уточнил на счёт «не в лом» :) А вообще имхо это не тот случай, когда нужно прибегать к Си, потому что больше затрахаешься, чем профита словишь.

soko1 ★★★★★
() автор топика
Ответ на: комментарий от gv

if нужен для повторных прогонов. А ТСу пока надо просто одноразово (иначе был бы не bash-script) обработать кучу файлов.

anonymous
()
Ответ на: комментарий от anonymous

if нужен для повторных прогонов. А ТСу пока надо просто одноразово (иначе был бы не bash-script) обработать кучу файлов.

Ясно. В качестве юмора вот решение с проверкой для повторных прогонов, но в один пайплайн и без средств баша:

$ tree -A
.
└── subdir
    ├── 1.mp4
    ├── 1.mp4.png
    ├── 2.mp4
    ├── 2.mp4.png
    ├── 3.mp4
    └── 4.mp4

$ find -name '*.png' -print0 | sed -r -e 's:([^\x0]*)\.png\x0:-not\x0-path\x0\1\x0:g' -e 's:$:\0-print0:' | xargs -0 find -name '*.mp4' | xargs -0 -L1 -I{} echo ffmpeg -i {} {}.png
ffmpeg -i ./subdir/3.mp4 ./subdir/3.mp4.png
ffmpeg -i ./subdir/4.mp4 ./subdir/4.mp4.png

$

Кончено же я не советую ТС так делать :)

gv
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.