Нехай сценарій Bash чекає повідомлення про стан, перш ніж продовжувати


10

Я запускаю сервер Selenium за допомогою скрипту bash, і як ви бачите із часових позначок журналу нижче, потрібні приблизно 32 секунди, щоб річ повністю вийшла в Інтернет:

Feb 28, 2012 10:19:02 PM org.openqa.grid.selenium.GridLauncher main
INFO: Launching a standalone server
22:19:02.835 INFO - Java: Sun Microsystems Inc. 20.0-b11
22:19:02.836 INFO - OS: Linux 2.6.32-220.4.1.el6.x86_64 amd64
22:19:02.852 INFO - v2.19.0, with Core v2.19.0. Built from revision 15849
22:19:02.988 INFO - RemoteWebDriver instances should connect to: http://127.0.0.1:4444/wd/hub
22:19:02.990 INFO - Version Jetty/5.1.x
22:19:02.992 INFO - Started HttpContext[/selenium-server/driver,/selenium-server/driver]
22:19:02.993 INFO - Started HttpContext[/selenium-server,/selenium-server]
22:19:02.993 INFO - Started HttpContext[/,/]
22:19:34.552 INFO - Started org.openqa.jetty.jetty.servlet.ServletHandler@488e32e7
22:19:34.552 INFO - Started HttpContext[/wd,/wd]
22:19:34.555 INFO - Started SocketListener on 0.0.0.0:4444
22:19:34.555 INFO - Started org.openqa.jetty.jetty.Server@7d29f3b5

Замість використання команди "sleep 32" після запуску сервера (щоб затримати скрипт перед тим, як рухатися далі), я хотів би, щоб мій скрипт bash зачекав, поки він не побачить рядок "Started SocketListener", а потім продовжити. Це можливо?

Відповіді:


8

Ви можете використовувати tail -fдля продовження читання з файлу під час його зростання. Будьте уважні до того, чим харчуєтесь tail -f. Ви можете tail -fподати в фільтр, який чекає, поки потрібний рядок журналу не закриється. Що не буде працювати, якщо ви вставляєте tail -fу фільтр, який передається в інший фільтр, тому що проміжний фільтр захищає його вихід. Це працює:

: >file.log  # create an empty log file
start-selenium-session --log-file=file.log &
{ tail -n +1 -f file.log & } | sed -n '/Started SocketListener/q'
speak-to-socket

Зауважте, що я ставлю tailна задній план. Це тому, що коли sedзнаходить потрібну лінію, вона виходить, але конвеєр продовжує працювати, поки tailчекає наступного рядка, який може не з’явитися одразу, якщо взагалі¹. tailвийде, коли прийде наступний рядок, і він отримає SIGPIPE. Це може залишити блукаючий tailпроцес, якщо журнал буде видалено, не записуючи до нього жодного рядка (отримання PID tailпроцесу, щоб знищити його при sedвиході, можливо, але складно).

¹ Дякую Peter.O за вказівку на помилку в попередній версії.


Примітка (педантність, можливо) - я не знаю жодних оболонок, які насправді потребують вуапа, щоб дозволити писати порожній файл.
Кріс Даун

@ChrisDown Я також не вважаю, але мені здається, що ясніше писати но-оп явно.
Жил "ТАК - перестань бути злим"

Приємно (+1) ... кажучи про буфери: я не розумію буферних махінацій, але у нього є одне питання, якщо цільову лінію не одразу слід більше рядків журналу. Він висить, поки не буде записано більше рядків, навіть якщо sed вже збігався з шаблоном (<- я не розумію цієї частини). Змінена sedкоманда, яка достатньо записує в журнал, щоб примусити флеш (?), Робить її негайно (я тестував її), але я думаю, що є можливість вставлених даних перемежовуватися з рядком сеансу селену .. .
Пітер.О

@ Peter.O IIRC деякі реалізації sed прочитали наступний рядок заздалегідь, тому що є випадки, коли це корисно ( $адреса для одного). Я не бачив, щоб це сталося в моїх тестах (з GNU sed). Як саме ви виявили помилку, на якій ОС?
Жил "ТАК - перестань бути злим"

@Gilles: paste.ubuntu.com/863326 .. і: GNU sed версія 4.2.1 , хвіст (GNU coreutils) 7.4
Peter.O

3

У сценарії прямої оболонки трохи складніше, але це те, що я досить довго використовував для tomcat та oc4j:

perlscr='
alarm 120;
open F, "<$ARGV[0]";
seek F -($ARGV[1]*80),2;
while (1) {exit if (<F>=~$ARGV[2]);}'

window=10
scanfor="^INFO: Server startup in \d+ ms"
perl -e "$perlscr" $logfile $window "$scanfor" 2>&1 0<&1

alarmОброблятиме будь-який потенційний повішення , де не вдався кіт. Кількість рядків для повернення з EOF регулюється (з конфігураційного файлу).

Зрештою я перемістив всю річ на пітон; хоча він трохи довший, він трохи ефективніший:

class Alarm:
    import signal
    signal_signal = signal.signal
    signal_SIGALRM = signal.SIGALRM
    signal_SIG_DFL = signal.SIG_DFL
    del signal
    def __init__(self, delay)
       self.howlong = delay
       self.clear()
    def __del__(self):
       self.reset_signals()
    def __nonzero__(self):
       return self.state
    def clear(self):
       self.state = False
       self.reset_signals()
    def _start_alarm(self):
       from signal import alarm
       alarm(self.howlong)
    def _set_sigalarm(self, handler):
        if handler:
            self.signal_signal(self.signal_SIGALRM, handler)
        else:
            self.signal_signal(self.signal_SIGALRM, self.signal_SIG_DFL)
    def reset_signals(self):
        self._set_sigalarm(None)
    def set_signals(self):
        self._set_sigalarm(self.handler)
    def handler(self, signo, frame):
        self.state = False
    def start(self):
        self.state = True
        self.set_signals()
        self._start_alarm()
    def stop(self):
        self.reset_signals()
        self.state = False
found = False
scanfor = re.compile('^INFO: Server startup in \d+ ms')
window = 10
logfile = open(logfilename, 'r')
logfile.seek(window * 80, 2)
alarm = Alarm(timeout)
try:
    alarm.start()
    while alarm:
        line = logfile.readline()
        if line:
            m = scanfor.search(line)
            if m:
                alarm.stop()
                found = True
                break
        time.sleep(0.1)
finally:
    alarm.clear()

1

Ви можете додати це до свого сценарію, щоб реалізувати паузу:

perl -e 'use File::Tail;
    my $ref=tie *FH,"File::Tail",(name=>"/var/log/messages",maxinterval=>1);
    while(<FH>) { exit if /Started SocketListener/ };'

Він використовує модуль perl Файл :: Хвіст так, як він веде себе tail -f logfile | grep Started SocketListener.

Замініть / var / log / message відповідним файлом журналу. Зауважте, що він вічно зависне, якщо "Started SocketListener" ніколи не з’явиться.


1

Можливо, вам слід використовувати тайм-аут, а не чекати нескінченно.

Функція bash нижче буде блокована, поки не з’явиться заданий пошуковий термін або не буде досягнуто заданого часу.

Стан виходу дорівнюватиме 0, якщо рядок буде знайдено протягом часу.

wait_str() {
  local file="$1"; shift
  local search_term="$1"; shift
  local wait_time="${1:-5m}"; shift # 5 minutes as default timeout

  (timeout $wait_time tail -F -n0 "$file" &) | grep -q "$search_term" && return 0

  echo "Timeout of $wait_time reached. Unable to find '$search_term' in '$file'"
  return 1
}

Можливо, файл журналу ще не існує лише після запуску Selenium. У такому випадку слід зачекати, коли він з’явиться, перш ніж шукати рядок:

wait_selenium_server() {
  echo "Waiting for Selenium server..."
  local server_log="$1"; shift
  local wait_time="$1"; shift

  wait_file "$server_log" 10 || { echo "Selenium log file missing: '$server_log'"; return 1; }

  wait_str "$server_log" "Started SocketListener" "$wait_time"
}

wait_file() {
  local file="$1"; shift
  local wait_seconds="${1:-10}"; shift # 10 seconds as default timeout

  until test $((wait_seconds--)) -eq 0 -o -f "$file" ; do sleep 1; done

  ((++wait_seconds))
}

Ось як ви можете ним користуватися:

wait_selenium_server "/var/log/selenium.log" 5m && \
echo -e "\n-------------------------- Selenium READY --------------------------\n"
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.