LINUX.ORG.RU
решено ФорумAdmin

Ожидание завершения всех процессов screen

 ,


1

2

CentOS7. Есть скрипт, который ожидает завершения всех скринов данного юзера, имена которых совпадают и именами определённых папок. Всё бы работало, да только меня смущает мой костыль из 2-х грепов и то, что, как я понял, у переменной wt своя зона видимости (с учётом того, что в if будет true) так как если поставить перед концом главного цикла 'echo $wt' мы получим всегда 'skip' а если поставить после 'sleep 5' то всегда 'wait'.

Сейчас у меня даже если '$server == $screen' «Waiting for $server» у меня появляется 1 раз при любом sleep и оставшимся screen консолью, а надо подправить так, чтобы «пока у данного пользователя в screen есть консоли, имя у которых равны этим папкам — ждать». Также я бы хотел узнать более «эстетичный» способ находжения имён консолек скринов. Так как я недавно начал разбираться в баше и его скриптинге я, скорее всего, упустил какую-то очевидную деталь.

  wt='wait'
  while [ $wt == 'wait' ]
  do
    wt='skip'
    ls /opt/msm/servers | while read server
    do
      sudo -u msm screen -ls | grep -Eo "^[[:space:]][0-9]+\.[A-Za-z0-9_-]+" | grep -Eo "[A-Za-z0-9_-]+$" | while read screen
      do
        if [ $server == $screen ] ;
        then
          wt='wait'
          echo "Waiting for $server"
          sleep 5
        fi
      done
    done
  done

Ну тот же самый алгоритм может выглядеть как-то так:

#!/bin/bash

wait=1
while [[ $wait ]]; do
    unset wait
    for server_file in /opt/msm/servers/*; do
        for screen_file in /var/run/screen/S-msm/*; do
            IFS='.' read pid sessionname <<< "${screen_file##*/}"
            if [[ ${server_file##*/} == $sessionname ]]; then
                wait=1
                printf >&2 'Wainting for %s\n' "$sessionname"
                sleep 5
            fi
        done
    done
done

(Не проверял. Могут быть ошибки вплоть до синтаксических.)

Но вообще ожидать завершения процессов разумнее по их идентификаторам (PID’ам), а вовсе не по файлам, которые они за собой должны убирать, но могут и не убрать — как получить pid сессии «Скрина» я вам уже подсказал, про сервера — это только вы знаете.

Zmicier ★★★★★
()
Последнее исправление: Zmicier (всего исправлений: 1)

Ну и пара замечаний, что могут быть вам, как человеку, что «недавно начал разбираться в Баше», полезны:

ls /opt/msm/servers | while read server

Вывод ls в общем случае просто не предназначен для разбора машиной, и а в вашем случае и ему подобным, как вы поняли, совершенно не нужен.

[ $server == $screen ]

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

Zmicier ★★★★★
()

Вернусь сюда еще немного, и чтоб у вас не осталось впечатление, что это сейчас просто так повезло, а вообще вызывать grep для разбора строки — это нормально, покажу, как можно было б аккуратно разобрать вывод $ screen -ls, если бы по каким-то причинам мы не могли напрямую обратиться к файлам:

while read; do
    [[ $REPLY == $'\t'* ]] || continue
    IFS+='.' read pid sessionname __ <<< "$REPLY"
    printf '%s\n' "$sessionname"
done < \
     <(screen -ls)
Zmicier ★★★★★
()
Последнее исправление: Zmicier (всего исправлений: 3)
Ответ на: комментарий от Zmicier

Таки! /var/run/screen/S-msm/* Щас будем пробовать. Спасибо.

А что до сервера — у него может быть не один процесс, а скрипт запуска/остановки изначально был нацелен на отображение статуса работоспособности в работающем скрине (врублен сервер — работает скрин иначе скрин не работает) => лучше чекать не по пиду а по состоянию скрина.

Кстать, тема про ввод screen -ls через <, а не через пайплайн понравилась. Только зачем там два раза <. (ведь '\' это фактически «команда не закончена, дочитай её со следующей строки» и в итоге у нас while ... done < \n <(screen -ls))

В устаревших одиночных скобках ...

Где можно взять мануал по «новым» технологиям?

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

Где можно взять мануал по «новым» технологиям?

На свалке истории. А мануал по новым технологиям для написания простых скриптов можно взять здесь: https://docs.python.org/3/

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

Кстать, тема про ввод screen -ls через <, а не через пайплайн понравилась. Только зачем там два раза <.

Первый — перенаправление ввода, второй — один символ из оператора <(), см. (info "(bash) Process Substitution").

(ведь '\' это фактически «команда не закончена, дочитай её со следующей строки» и в итоге у нас while ... done < \n <(screen -ls))

Наоборот. Это эквивалент while ... done < <(screen -ls)), безо всяких переводов строки. А я такие конструкции всегда разбиваю на две строки, просто потому, что мне кажется, что так понятнее.

Где можно взять мануал по «новым» технологиям?

Да они давно уже не новые. А справочное руководство по ГНУ Башу — разумеется, поставляется вместе с Башем: M-x info RET m bash RET, $ info bash, /usr/share/doc/bash/bashref.html, /usr/share/doc/bash/bashref.pdf, но если хочется в онлайне, то можно взять тут: https://www.gnu.org/software/bash/manual/

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

Но вообще ожидать завершения процессов разумнее по их идентификаторам (PID’ам)

Ну а собственно давайте напишем. Вот, по-моему оно еще и много понятнее:

#!/bin/bash

procwait ()
{
    while kill 2>&- -0 "$1"; do
        sleep 5
    done
}

cd '/var/run/screen/S-msm/'
for screen_file in *; do
    IFS='.' read pid sessionname <<< "$screen_file"
    if [[ -e "/opt/msm/servers/$sessionname" ]]; then
        printf >&2 'Wainting for %s\n' "$sessionname"
        procwait "$pid" &
    fi
done
wait

Опять же — не проверял.

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

Работает!

Подредачив свой код я получил желаемый результат.

Вот что получилось:

msm_allstop() {
  while read server
  do
    /opt/msm/bin/msm stop $server
  done < \
       <(cat /opt/msm/enabled)

  wait=1
  while [[ $wait ]]
  do
    unset wait
    for server in /opt/msm/servers/*
    do
      for screen in /var/run/screen/S-msm/*
      do
        IFS='.' read pid screen <<< "${screen##*/}"
        if [[ ${server##*/} == $screen ]]
        then
          wait=1
          echo "Waiting for ${server##*/}"
          sleep 5
        fi
      done
    done
  done

  echo 'Done.'
}
Консоль:
$ sudo service msm start && sudo service msm stop
Starting iwbtb-main...
iwbtb-main is now running.
Starting gjp-main...
gjp-main is now running.
Stopping iwbtb-main...
Waiting for iwbtb-main
Stopping gjp-main...
Waiting for gjp-main
...
Waiting for gjp-main
Waiting for gjp-main
Done.

Выдайте Zmicier'у медаль))

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

В /opt/msm/servers (папка) более 20 серверов(папка с бинарниками серва) с разными настройками и владельцами(через ftp)

В /opt/msm/enable (файл!) имена серверов(их папок), разделённых \n которые необходимо запускать при старте машины. (да, знаю. есть ln -s, но именно файл удобнее редачить и через ftp, и через tomcat)

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

А вариант с параллельным ожиданием процессов вы не проверяли?

А смысл? Алгоритм работает по самому медленному элементу массива, же.

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

В /opt/msm/servers (папка) более 20 серверов...
В /opt/msm/enable (файл!) имена серверов...

Пардон, я не понял, что́ вы сказать-то хотите?

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

А вариант с параллельным ожиданием процессов вы не проверяли?

А смысл?

Чтобы выяснить, работает он или нет, и сообщить мне, например.

Zmicier ★★★★★
()
15 сентября 2016 г.
Ответ на: комментарий от Zmicier

Объединил оба метода проверки. Всё работает. Спасибо. (извиняй, что сразу не ответил. не чекал форум)

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