LINUX.ORG.RU
ФорумAdmin

nginx-rtmp-module как поднять поток после недоступности RTSP-источника более 5 минут

 , , , ,


0

2

Здравствуйте, уважаемые форумчане. Прошу вас помочь по следующему вопросу.

Я установил nginx плюс nginx-rtmp-module вот таким образом, немного откорректировал, добавил функцию записи RTMP потока в файлы «*.flv» размером 50 Мб. Записывается в папку «/mnt» в виде «stream-2016-08-11--16-56-44.flv». Когда RTSP-источник становится недоступен в течении 10-20 секунд - запись начинается в новый файл.

Проблема состоит в том, что если RTSP-источник становится недоступен в течении 5 минут и дольше, запись не возобновляется автоматически, нужно только, например, перезапустить nginx командой «service nginx restart».

Что нужно дописать в этот конфиг, чтобы после потери-восстановлении связи с RTSP-источником запись возобновилась автоматически?

Вот содержимое моего «/etc/nginx/nginx.conf»

user orangepi;
worker_processes 1;
 
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
 
events {
  worker_connections 1024;
}
 
http {
  include /etc/nginx/mime.types;
  default_type application/octet-stream;
 
  log_format main '$remote_addr - $remote_user [$time_local] "$request" '
  '$status $body_bytes_sent "$http_referer" '
  '"$http_user_agent" "$http_x_forwarded_for"';
 
  access_log /var/log/nginx/access.log main;
  sendfile on;
  #tcp_nopush on;
  keepalive_timeout 65;
  #gzip on;
 
  server {
    listen 80;
    # rtmp stat
    location /stat {
     rtmp_stat all;
     rtmp_stat_stylesheet stat.xsl;
    }
 
    location /stat.xsl {
     # you can move stat.xsl to a different location
     root /etc/nginx/;
    }
 
    location / {
     rtmp_control all;
    }
 
    error_page 500 502 503 504 /50x.html;
    location = /50x.html {
    root html;
  }

  location /image/cam1/ {
    proxy_pass "http://video-service.in.ua/wp-content/uploads/2014/08/b1072-k_.jpg";
  }
 }
 include /etc/nginx/conf.d/*.conf;
}

 
rtmp {
    server {
        listen 1935;
	ping 30s;
	notify_method get; 

application cam1 {
        live on;
recorder cam01 {
record all;
record_path /mnt;
record_suffix -%Y-%m-%d--%H-%M-%S.flv;
record_max_size 51200K;
exec_record_done flvmeta -U -f $path;
}
exec_static /usr/local/bin/ffmpeg -rtsp_transport tcp -i rtsp://admin:123456@192.168.0.125:1005/mpeg4 -c copy -an -f flv rtmp://localhost:1935/cam1/stream;
    }
  }
}

Ответ на: комментарий от goingUp

Если проблема только с записью, как вариант, можно записывать с помощью ffmpeg.

Запись работает отлично по схеме:

Соединение [1-4]:
[1]IP-camera(rtsp) -> [2]FFmpeg(rtsp->rtmp) -> [3]Nginx(nginx-rtmp-module) -> [4]FlvRecorder(rtmp)

Когда отключаю Ethernet-кабель (RJ45) от IP-камеры (rtsp) и через 1-20 секунд подключаю обратно - то соединение [1-4] восстанавливается.

Если IP-камера была оффлайн 5 и более минут - то соединение [1-4] НЕ восстанавливается.

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

При записи с помощью ffmpeg присутствует такая же проблема, как только RTSP-поток, с которого пишет ffmpeg, становится недоступен на 2 минуты - запись обрывается навсегда.

В том то и вопрос, как сделать чтобы запись возобновлялась после появления в онлайне RTSP-потока после 2-х минут недоступности?

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

А вы в этом тесте брали поток с nginx, или с камеры? Было бы неплохо узнать, в каком месте этого конвеера появляется проблема. Висит ли ffmpeg из exec_static в списке процессов?

goingUp ★★★★★
()
Последнее исправление: goingUp (всего исправлений: 1)
Ответ на: комментарий от pospelov

Сделал вот такой скрипт, который перезагружает nginx когда камера переходит из оффлайна в онлайн:

#!/bin/bash

ip_address1=192.168.0.125
counts=0 # делать рестарт после указанного числа проверок, 0=всегда

while [ 1 ]; do # объявляем бесконечный цикл

 if ping -q -c 1 -n $ip_address1 # проверяем пингуется ли камера
  then

  while ping -q -c 1 -n $ip_address1 # если пингуется, - ждем пока перестанет пинговаться
   do
   echo 'online'
   sleep 1
   done

 fi

  echo 'offline'
  count=1

  while ! ping -q -c 1 -n $ip_address1 # ждем когда появится пинг от камеры
   do
   echo 'offline'
   count=$(( $count + 1 ))
   done

 if [ "$count" -gt "$counts" ]
  then
   service nginx stop # когда появился пинг от камеры - перезагружаем nginx, убиваем ffmpeg
   killall -INT ffmpeg
   killall ffmpeg
   service nginx start
 fi

done

exit 0
Теперь его надо засунуть в автозагрузку и заставить его контролировать несколько камер, как это сделать?

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

Можно сделать цикл по айпишникам камер, но сам скрипт придется немного переделать чтоб посылалось по пакету на каждую камеру, то есть просто завернуть в цикл имеющийся скрипт не получится.

for camera in 192.168.1.1 192.168.1.2 192.168.1.3
do
  if ping -q -c 1 -n $camera
    do
    <...>
done

while [ 1 ] «красивее» будет while true или while :.

Как положить в автозапуск зависит от используемой системы инициализации - в случае systemd пишите юнит, в случае sysv можно просто в /etc/rc.local положить вызов скрипта (только не забудьте nohup и амперсанд чтоб он не повесил машину).

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

просто завернуть в цикл имеющийся скрипт не получится

А если весь скрипт засунуть в функцию my_function с параметром ip_address, а потом запускать несколько раз эту функцию одновременно?

my_function(192.168.0.124) & my_function(192.168.0.125) & my_function(192.168.0.126)
Так получится?

Еще ко всему этому делу мне нужно написать «скрипт-удалятор» самого старого файла из указанной папки, когда свободное место на диске, на котором лежит эта папка менее 1 Гб. Может у кого есть наброски?

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

Так получится?

Получится.

Может у кого есть наброски?

Ну для удаления хоть вот такой нагугленный вариант http://unix.stackexchange.com/questions/35792/bash-remove-oldest-files (первый ответ), место на диске можно смотреть df'ом, тоже не кажется сложным.

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

запихал в функцию:

#!/bin/bash

proverka () {

 if [ "$1" ]
 then
  ip_address1=$1
  echo $ip_address1
 fi

counts=0 # делать рестарт после указанного числа проверок, 0=всегда

while true; do # объявляем бесконечный цикл

 if ping -q -c 1 -n $ip_address1 # проверяем пингуется ли камера
  then

  while ping -q -c 1 -n $ip_address1 # если пингуется, - ждем пока перестанет пинговаться
   do
   echo $ip_address1
   echo 'online'
   sleep 1
   done

 fi

  echo $ip_address1
  echo 'offline'
  count=1

  while ! ping -q -c 1 -n $ip_address1 # ждем когда появится пинг от камеры
   do
   echo $ip_address1
   echo 'offline'
   count=$(( $count + 1 ))
   done

 if [ "$count" -gt "$counts" ]
  then

  service nginx stop # когда появился пинг от камеры - перезапускаем nginx, убиваем ffmpeg
  echo '------service nginx stop-----'
  killall -INT ffmpeg
  killall ffmpeg
  service nginx start
  echo '-----service nginx start-----'

 fi

done
}

proverka 192.168.0.125

exit 0

но если вызываю так: proverka 192.168.0.125 & proverka 192.168.0.126, то запускается скрипт и я его не могу остановить с помощью Ctrl+C, это нормально? выполнит ли он в таком случае поставленную задачу? если да, то как останавливать?

можно просто в /etc/rc.local положить вызов скрипта (только не забудьте nohup и амперсанд чтоб он не повесил машину).

Вот здесь можно подробнее? Если у меня скрипт sh /usr/local/bin/10.sh, мне эту строку вписать как есть в /etc/rc.local или так sh /usr/local/bin/10.sh nohup? или как?

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

По первому вопросу - несколько раз нажмите ^C, там же вложенные циклы и прочая лабуда, то есть одним нажатием ^C убивается, скажем, пинг, и цикл идет на второй круг. Если это критично то это можно исправить, но если не планируется руками его постоянно запускать то и так можно оставить.

По второму вопросу - в /etc/rc.local перед exit 0 добавьте nohup /usr/local/bin/10.sh &. sh не нужно потому что у вас вообще в sha-bang (первая строчка с #!) написано его через bash выполнять. Только права на выполнение надо дать скрипту:

chmod +x /usr/local/bin/10.sh
alozovskoy ★★★★★
()
Ответ на: комментарий от alozovskoy

Спасибо огромное за ответы!

1. Я пробовал нажимать Ctrl+C много раз подряд, более 3-х, но он все равно не останавливается. Как еще можно организовать остановку программы?

2. Если я хочу чтобы строки с айпишниками были вверху скрипта, то я так понимаю можно сделать вот так:

#!/bin/bash

my_prog () { 
proverka 192.168.0.125 & proverka 192.168.0.126
}

proverka () { ... }

my_prog

exit 0
правильно?

3. Если в пункте 2. все правильно, значит можно при вызове my_prog указать ему nohup и &, например, вот так:

nohup my_prog &
и еще добавить что-то для решения вопроса в пункте 1. Правильно?

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

1. Простого случая нет, по сути нужно отслеживать коды завершения подпрограмм и выходить из циклов, но там как тот же пинг может вернуть ненулевой код (в случае недоступности хоста) то придется городить кучу проверок.

2. Да, это будет работать.

3. Ну это поможет по ctrl+C убить скрипт, да, но все что отправили в background при помощи амперсанда будет висеть.

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

все что отправили в background при помощи амперсанда будет висеть

при этом появится возможность прибить его

killall 10.sh
так?

P.S. Сейчас уже нет возможности проверить, экспериментировать завтра начну уже...

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

Нет. 10.sh это имя вашего скрипта, в том же ping'е этого имени не будет, так что таким способом убить не получится. Плюс при таком запуске и ppid (идентификатор родительского процесса) будет 1, так что сделать выборку по pid'у скрипта 10.sh тоже не получится.

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

Спасибо Вам. Буду дальше думать. Наверное, с учетом того что он автостартовать в фоне будет, оставлю его запуск как есть. А в my_prog добавлю параллельно запуск функции udalyator которая будет через каждые N минут удалять самый старый файл из указанной папки, если свободное место на диске, на котором лежит эта папка, менее X Мб.

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

Написал скрипт-удалятор, который пока свободное место на диске не X байт находит и удаляет самый старый flv-файл

#!/bin/bash
work_dir="/mnt/disc" # папка, в которую смонтирован съемный диск
min_available=25724352 # лимит - это минимальное количество байт, которое будет свободно на диске в результате работы скрипта
log_file="/mnt/del_sh.log" # путь к лог-файлу

available=$(df $work_dir | awk NR\ ==\ 2\{print\ \$4\}) # вычисляем свободное место на диске, который смонтирован в папку /mnt/disc

echo $(date +"%Y.%m.%d-%H:%M:%S")" | "$available - $min_available" = "$(( $available - $min_available ))  >> $log_file # записываем разницу между занятым простр. и лимитом

while [ "$min_available" -gt "$available" ] # цикл, выполняемый пока не будет соблюден лимит
do

file_name=$(find $work_dir -name "*.flv" -exec stat -c "%Y %n" {} \; | sort -n | head -1 | cut -d' ' -f2) # ищем имя самого старого файла
rm $file_name # удаляем найденный файл
echo $(date +"%Y.%m.%d-%H:%M:%S")" | "$file_name" - File has been deleted" >> $log_file # записываем какой файл когда удален

sleep 1 # ждем 1 секунду
echo $(date +"%Y.%m.%d-%H:%M:%S")" | sleep 1" >> $log_file # отображаем это в лог-файле

available=$(df $work_dir | awk NR\ ==\ 2\{print\ \$4\}) # вычисляем свободное место на диске, который смонтирован в папку /mnt/disc
echo $(date +"%Y.%m.%d-%H:%M:%S")" | "$available - $min_available" = "$(( $available - $min_available )) >> $log_file # записываем вычисления доступных для записи байт в log

done
echo "--------------------+----------------------------------------------------------------------------" >> $log_file # конец работы скрипта пишем в лог-файл

вот так выглядит лог-файл

--------------------+----------------------------------------------------------------------------
2016.08.23-11:58:09 | 25266464 - 25724352 = -457888
2016.08.23-11:58:10 | /mnt/disc/cam2/stream-cam2-2016-08-22--21-11-14.flv - File has been deleted
2016.08.23-11:58:11 | sleep 1
2016.08.23-11:58:11 | 25452000 - 25724352 = -272352
2016.08.23-11:58:12 | /mnt/disc/cam1/stream-cam1-2016-08-22--21-13-45.flv - File has been deleted
2016.08.23-11:58:13 | sleep 1
2016.08.23-11:58:13 | 25675648 - 25724352 = -48704
2016.08.23-11:58:14 | /mnt/disc/cam3/stream-cam3-2016-08-22--21-21-00.flv - File has been deleted
2016.08.23-11:58:15 | sleep 1
2016.08.23-11:58:15 | 25861024 - 25724352 = 136672
--------------------+----------------------------------------------------------------------------
2016.08.23-12:08:11 | 25266048 - 25724352 = -458304
2016.08.23-12:08:12 | /mnt/disc/cam2/stream-cam2-2016-08-22--21-21-15.flv - File has been deleted
2016.08.23-12:08:13 | sleep 1
2016.08.23-12:08:13 | 25451488 - 25724352 = -272864
2016.08.23-12:08:15 | /mnt/disc/cam1/stream-cam1-2016-08-22--21-23-47.flv - File has been deleted
2016.08.23-12:08:16 | sleep 1
2016.08.23-12:08:16 | 25674752 - 25724352 = -49600
2016.08.23-12:08:17 | /mnt/disc/cam3/stream-cam3-2016-08-22--21-31-01.flv - File has been deleted
2016.08.23-12:08:18 | sleep 1
2016.08.23-12:08:18 | 25860672 - 25724352 = 136320
--------------------+----------------------------------------------------------------------------
2016.08.23-12:18:12 | 25268192 - 25724352 = -456160
2016.08.23-12:18:13 | /mnt/disc/cam2/stream-cam2-2016-08-22--21-31-16.flv - File has been deleted
2016.08.23-12:18:14 | sleep 1
2016.08.23-12:18:14 | 25453760 - 25724352 = -270592
2016.08.23-12:18:15 | /mnt/disc/cam1/stream-cam1-2016-08-22--21-33-49.flv - File has been deleted
2016.08.23-12:18:16 | sleep 1
2016.08.23-12:18:16 | 25677728 - 25724352 = -46624
2016.08.23-12:18:17 | /mnt/disc/cam3/stream-cam3-2016-08-22--21-41-02.flv - File has been deleted
2016.08.23-12:18:18 | sleep 1
2016.08.23-12:18:18 | 25863552 - 25724352 = 139200
--------------------+----------------------------------------------------------------------------

Запускается он nginx-ом в тот момент, когда закончилась запись очередного 10-ти минутного flv-файла с IP-камеры №1. Для этого в файл /etc/nginx/nginx.conf добавляется вот такая строка:

exec_record_done sh /mnt/del.sh;

в разделе, отвечающем за конкретную камеру

rtmp {
     server {
            ...
            application cam1 {
                              ...
                              recorder cam01 {
                                             record all;
                                             ...
                                             exec_record_done sh /mnt/del.sh;
                                             ...

Но камер у меня уже 3 штуки, и конкретно первая может не работать, это означает что скрипт-удалятор при этом тоже не будет работать. Нужно его строку запуска exec_record_done sh /mnt/del.sh; указать в каждой камере. Но в этом случае может быть одновременно запущено несколько копий скрипта, а этого нельзя допустить.

Вопрос №1: Как можно организовать проверку наличия уже запущенной на выполнение копии этого скрипта?

Была идея создать файл «flag.txt» и в него писать в начале выполнения «1», а в конце выполнения «0». А перед началом любых действий проверять что записано в этом файле, если «0» то запускаться, если «1» - то на выход. Но в этом случае он «протрет дырку на диске».

Вопрос №2: Можно ли в оперативной памяти как-то осуществить аналогичную проверку?

Вопрос №3: В общем нормально ли написан данный скрипт? Если нет укажите на недостатки, пожалуйста.

Меня смущает метод получения цифры, которая равна количеству свободных байт на диске, который смонтирован в папку с именем в переменной $work_dir

Сначала выполняется команда df в результате возвращается таблица на 6 столбцов и много строк

Filesystem     1K-blocks     Used Available Use% Mounted on
/dev/mmcblk0p2  15235440  2266720  12338016  16% /
none              380812        0    380812   0% /dev
tmpfs             513576        0    513576   0% /dev/shm
tmpfs             513576    13300    500276   3% /run
tmpfs               5120        4      5116   1% /run/lock
tmpfs             513576        0    513576   0% /sys/fs/cgroup
tmpfs             513576        8    513568   1% /tmp
/dev/mmcblk0p1     64511    31835     32677  50% /media/boot
tmpfs             102716        0    102716   0% /run/user/107
/dev/sda1       78153152 52772512  25380640  68% /mnt/disc
tmpfs             102716        0    102716   0% /run/user/1000

Если при этом указывается имя папки, в которую смонтирован нужный съемный диск df /mnt/disc , то у таблицы будет 6 столбцов и только 2 строки, первая - заголовки столбцов, вторая - данные, соответствующие этим заголовкам

Filesystem     1K-blocks     Used Available Use% Mounted on
/dev/sda1       78153152 52234720  25918432  67% /mnt/disc

Далее с помощью «awk» из этой таблицы вытягиваем ячейку в 4-м столбце, 2-й строке

df /mnt/disc | awk NR\ ==\ 2\{print\ \$4\}
25918432

Вопрос №4: Есть ли другие методы получить цифру, равную количеству байт свободного дискового пространства? Если есть то какие?

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

1. Обычно для этого используют lock-файлы. Предложенная идея с файлом правильная, только обычно туда пишут PID процесса чтоб в случае если скрипт свалился не почистив lock-файл при следующем запуске это отследить и выполнить работу. Реализации гуглятся, в целом делают кому как удобнее.

С учетом того сколько в логи пишется о ресурсе диска я бы не беспокоился.

2. Ну можно просто ps парсить, но можно и в tmpfs хранить (это диск в RAM).

3. Про df - посмотрите ман, есть возможность через ключ --output указать какие именно столбцы нужно выводить (просто чтоб меньше парсить). Можно еще парсить /proc/diskstats, но это не так удобно.

В целом по скрипту вроде все хорошо.

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

Спасибо. Я нашел здесь скрипт, который работает через lock-файл (в нем также есть парсинг ps), засунул его в «del1.sh», запускаю так: «sh del1.sh», пытаюсь в нем разобраться... То как я понял его выполнение - написал в #комментариях

#!/bin/bash
LOCK_FILE=/tmp/my_script.lock # путь к lock-файлу (как раз в RAM)

if [ -e $LOCK_FILE ] # если lock-файл существует
then # то ...
        PID=`cat $LOCK_FILE` # считываем его содержимое в переменную PID
        PID_NAME=`ps -p $PID -o comm=` # записывает в PID_NAME имя процесса с ID = PID, сюда к сожалению попадает имя - sh, а не - del1.sh
        if [ ! -z $PID_NAME ] # если PID_NAME это пустая строка -z вернет false, а ! -z вернет true
        then
                echo "Скрипт $0 найден в списке процессов"; ### здесь как я понял $0 - это имя запущенного скрипта, например - del1.sh
                exit 1;
        else
                echo "Обнаружен lock-файл с несуществующим ID процесса"
                rm $LOCK_FILE
        fi
fi
echo $$ > $LOCK_FILE

#######
#ДАЛЕЕ#
# КОД #
#######

sleep 10 # для проверки добавил имитацию выполнения кода

rm $LOCK_FILE
exit 0;

Меня в нем смущает результат, возвращаемый строкой PID_NAME=`ps -p $PID -o comm=`. Во первых не пойму что означает "-o comm=", во вторых эта строка возвращает «sh», а это еще не значит что это именно тот скрипт. Как исправить чтобы данная строка выводила имя, например «del1.sh», а не «sh» (не меняя при этом способ запуска)?

P.S. Как на этом форуме сделать разукрашенным вставленный код?

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

не пойму что означает "-o comm="

Ключ -o меняет заголовок, в данном случае так как указано пустое значение строчка с заголовком пропускается. В результате в выводе содержится только имя исполняемой программы. (Это в man ps есть все с примерами)

во вторых эта строка возвращает «sh», а это еще не значит что это именно тот скрипт. Как исправить чтобы данная строка выводила имя, например «del1.sh», а не «sh» (не меняя при этом способ запуска)?

Самый простой вариант это прочитать файл /proc/$PID/cmdline. Вообще то что эта команда возвращает это правильный ответ, потому что возвращается только имя команды без аргументов (которыми и является ваше имя скрипта)

P.S. Как на этом форуме сделать разукрашенным вставленный код?

В [code=bash]<ТУТ КОД>[/code] завернуть.

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

Спасибо большое! Я теперь понял, что в «PID_NAME» пишется имя, но оно не сверяется ни с чем, потом просто проверяется не пустая ли строка «PID_NAME», а что конкретно в ней написано уже не важно, главное чтоб не пусто :-)

Как я понял, если при попытке найти имя процесса с «PID» происходит ошибка, то строка «PID_NAME» остается пустой. А для программы важно только пустая или не пустая строка «PID_NAME», так?

Получилось у меня вот так:

#!/bin/bash
work_dir="/mnt/disc" # папка, в которую смонтирован съемный диск
min_available=25724352 # лимит - это минимальное количество байт, которое будет свободно на диске в результате работы скрипта
log_file="/mnt/del_sh.log" # путь к лог-файлу

#====================================== предотвращение запуска более одной копии данного скрипта ======================================
LOCK_FILE=/tmp/my_script_del_sh.lock # путь к lock-файлу (как раз в RAM)

if [ -e $LOCK_FILE ] # если lock-файл существует ...
then # то ...
        PID=`cat $LOCK_FILE` # считываем его содержимое в переменную PID
        PID_NAME=`ps -p $PID -o comm=` # записывает в PID_NAME имя процесса с ID = PID, сюда к сожалению попадает имя - sh, а не - del1.sh
        if [ ! -z $PID_NAME ] # если PID_NAME это пустая строка -z вернет false, а ! -z вернет true
        then
                ### echo "Скрипт $0 найден в списке процессов"; ### здесь как я понял $0 - это имя запущенного скрипта, например - del1.sh
                exit 1; # выход с кодом 1
        else
                ### echo "Обнаружен lock-файл с несуществующим ID процесса"
                rm $LOCK_FILE # если файл есть а процесса нет - удалить lock-файл
        fi
fi # если lock-файл НЕ существует просто работает дальше ...

echo $$ > $LOCK_FILE # записать текущий ID процесса в lock-файл
######## ДАЛЕЕ КОД ======================================================================================================================

available=$(df $work_dir | awk NR\ ==\ 2\{print\ \$4\}) # вычисляем свободное место на диске, который смонтирован в папку /mnt/disc
echo $(date +"%Y.%m.%d-%H:%M:%S")" | "$available - $min_available" = "$(( $available - $min_available ))  >> $log_file # записываем разницу между занятым простр. и лимитом

while [ "$min_available" -gt "$available" ] # цикл, выполняемый пока не будет соблюден лимит
do

file_name=$(find $work_dir -name "*.flv" -exec stat -c "%Y %n" {} \; | sort -n | head -1 | cut -d' ' -f2) # ищем имя самого старого файла
rm $file_name # удаляем найденный файл
echo $(date +"%Y.%m.%d-%H:%M:%S")" | "$file_name" - File has been deleted" >> $log_file # записываем какой файл когда удален

sleep 1 # ждем 1 секунду
echo $(date +"%Y.%m.%d-%H:%M:%S")" | sleep 1" >> $log_file # отображаем это в лог-файле

available=$(df $work_dir | awk NR\ ==\ 2\{print\ \$4\}) # вычисляем свободное место на диске, который смонтирован в папку /mnt/disc
echo $(date +"%Y.%m.%d-%H:%M:%S")" | "$available - $min_available" = "$(( $available - $min_available )) >> $log_file # записываем вычисления доступных для записи байт в log

done
echo "--------------------+----------------------------------------------------------------------------" >> $log_file # конец работы скрипта пишем в лог-файл

######## КОНЕЦ КОДА ======================================================================================================================
rm $LOCK_FILE # после выполнения кода и перед выходом - удалить lock-файл
exit 0;

Про df - посмотрите ман ...

буду дальше читать про df ...

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

Заменил это:

df $work_dir | awk NR\ ==\ 2\{print\ \$4\}
на это:
df $work_dir --output='avail' | tail -1
... вроде работает

Это нормальный вариант?

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

Нормальный, только я бы вот так сделал чтоб еще пробелы из полученной строки не вырезать

df $work_dir --output='avail' | grep -o "[0-9]*" 
alozovskoy ★★★★★
()
Ответ на: комментарий от alozovskoy

Добрый день, спасибо за подсказку! Вот этот метод предотвращения запуска нескольких копий скрипта мне не подошел. Этот метод нормально работает когда максимум 2 копии скрипта запускается, а их выполнение занимает длительное время. В моем случае скрипт запускается 3 раза одновременно, а время его работы составляет всего несколько секунд. Получается так: запустился первый, второй пытается - но останавливается, а третий запускается и работает параллельно с первым, и они одновременно вдвоем пытаются удалить одни и те же файлы. Об этом свидетельствуют записи в лог-файлах:

--------------------+----------------------------------------------------------------------------
2016.08.23-18:31:48 | 25230112 - 25724352 = -494240
2016.08.23-18:31:48 | 25230112 - 25724352 = -494240
2016.08.23-18:31:49 | /mnt/disc/cam1/stream-cam1-2016-08-23--03-35-38.flv - File has been deleted
2016.08.23-18:31:49 | /mnt/disc/cam1/stream-cam1-2016-08-23--03-35-38.flv - File has been deleted
2016.08.23-18:31:50 | sleep 1
2016.08.23-18:31:50 | 25454240 - 25724352 = -270112
2016.08.23-18:31:50 | sleep 1
2016.08.23-18:31:50 | 25454080 - 25724352 = -270272
2016.08.23-18:31:51 | /mnt/disc/cam3/stream-cam3-2016-08-23--03-41-37.flv - File has been deleted
2016.08.23-18:31:51 | /mnt/disc/cam3/stream-cam3-2016-08-23--03-41-37.flv - File has been deleted
2016.08.23-18:31:52 | sleep 1
2016.08.23-18:31:52 | 25639840 - 25724352 = -84512
2016.08.23-18:31:53 | sleep 1
2016.08.23-18:31:53 | 25639616 - 25724352 = -84736
2016.08.23-18:31:54 | /mnt/disc/cam2/stream-cam2-2016-08-23--03-41-50.flv - File has been deleted
2016.08.23-18:31:54 | /mnt/disc/cam2/stream-cam2-2016-08-23--03-41-50.flv - File has been deleted
2016.08.23-18:31:55 | sleep 1
2016.08.23-18:31:55 | 25823744 - 25724352 = 99392
--------------------+----------------------------------------------------------------------------
А одновременных запусков у меня предполагается около 10 штук. Вчера потратил весь день в попытках придумать правильный алгоритм и ничего умнее в голову не пришло кроме этого:
#!/bin/bash
LOCK_FILE=/tmp/del_sh.lock

if [ ! -e $LOCK_FILE ]
then
   echo $$ > $LOCK_FILE
      # основной код программы
   rm $LOCK_FILE
else
   echo $(date +"%Y.%m.%d-%H:%M:%S")" | lock-file currently exists" >> /mnt/log123.txt
fi
Проследил за отчетами - работает как надо. Но существует вероятность, хоть и очень маленькая, что скрипт умрет, не удалив при этом $LOCK_FILE.

Я попробовал вставить счетчик запусков скрипта, при которых $LOCK_FILE присутствовал в папке /tmp. Работало по принципу, если 9 запусков подряд файл все еще не удален, - значит что то не так, - удаляем его принудительно и работаем дальше. Но это ни к чему хорошему не привело, потому что счетчик тоже одновременно запускался в нескольких копиях, его надо перемещать в независимый отдельный скрипт, чего не особенно хочется делать. Будет «скрипт, который контролирует скрипт, который ...»

Есть ли еще какой-то вариант решения этой головоломки?

С учетом того сколько в логи пишется о ресурсе диска я бы не беспокоился.

Все строки с echo...log... будут только в процессе разработки. В рабочем варианте не будет никаких лог-файлов, перекуров sleep ... и закомментированных строк #...

P.S. Можно ли в конце скрипта не указывать строку exit 0;?

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

P.P.S. Искусственно увеличил время работы скрипта, чтобы найти файл /tmp/del_sh.lock, но не нашел его ни в папке /tmp ни поиском от каталога /, а вторая запущенная копия скрипта его видит и говорит что «lock-file currently exists»... что за полтергейст? Где он может быть?

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