Minta skrip Bash menunggu pesan status sebelum melanjutkan

10

Saya menjalankan server Selenium dengan skrip bash dan seperti yang dapat Anda lihat dari cap waktu pada log di bawah ini, dibutuhkan sekitar 32 detik untuk hal tersebut dapat sepenuhnya online:

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

Alih-alih menggunakan perintah "sleep 32" setelah memulai server (untuk menunda skrip sebelum melanjutkan), saya ingin skrip bash saya menunggu sampai ia melihat string "Mulai SocketListener", dan kemudian lanjutkan. Apakah itu mungkin?

Eric
sumber

Jawaban:

8

Anda dapat menggunakan tail -funtuk terus membaca dari file saat tumbuh. Hati-hati dengan apa yang Anda masukkan tail -f. Anda dapat menyalurkan tail -fke filter yang menunggu hingga baris log yang diinginkan dan berhenti. Apa yang tidak akan berhasil adalah jika Anda menyalurkan tail -fke filter yang menyalurkan ke filter lain, karena filter perantara akan buffer outputnya. Ini bekerja:

: >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

Perhatikan bahwa saya letakkan taildi latar belakang. Ini karena ketika sedmenemukan garis yang diinginkan, ia keluar, tetapi pipa tetap berjalan selama tailsedang menunggu baris berikutnya, yang mungkin tidak datang segera jika sama sekali¹. tailakan keluar ketika baris berikutnya datang dan menerima a SIGPIPE. Ini dapat meninggalkan tailproses yang menyimpang jika log dihapus tanpa ada baris yang ditulis untuk itu (memperoleh PID dari tailproses untuk membunuhnya ketika sedkeluar mungkin tetapi rumit).

¹ Terima kasih kepada Peter.O karena menunjukkan bug dalam versi sebelumnya.

Gilles 'SANGAT berhenti menjadi jahat'
sumber
Sebuah catatan (pedantry, mungkin) - Saya tidak tahu ada kerang yang benar-benar memerlukan noop untuk memungkinkan penulisan file kosong.
Chris Down
@ ChrisDown Saya juga tidak. Tapi saya merasa lebih jelas untuk menulis no-op secara eksplisit.
Gilles 'SANGAT berhenti menjadi jahat'
Bagus (+1) ... berbicara tentang buffer: Saya tidak mengerti intrik buffering, tetapi memang ada satu masalah yang harus diperhatikan, jika garis target tidak segera diikuti oleh lebih banyak baris log. Menggantung sampai lebih banyak baris ditulis, meskipun sed telah cocok dengan polanya (<- Aku tidak mengerti bagian itu). sedPerintah yang dimodifikasi yang menulis cukup untuk log untuk memaksa flush (?), Tidak menendang segera (saya mengujinya), tapi saya pikir itu memiliki kemungkinan data yang disisipkan untuk diselingi dengan garis sesi selenium .. .
Peter.O
@ Peter.O IIRC beberapa implementasi sed membaca baris berikutnya di muka, karena ada kasus di mana itu berguna ( $alamat, untuk satu). Saya tidak melihat itu terjadi dalam pengujian saya (dengan GNU sed). Bagaimana tepatnya Anda menunjukkan bug, pada OS apa?
Gilles 'SANGAT berhenti menjadi jahat'
@Gilles: paste.ubuntu.com/863326 .. dan: GNU sed versi 4.2.1 , tail (GNU coreutils) 7.4
Peter.O
3

Ini sedikit lebih sulit dalam skrip shell lurus, tapi ini yang saya gunakan cukup lama untuk kucing jantan dan 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

The alarmakan menangani setiap potensi gantung di mana tomcat gagal. Jumlah baris untuk kembali dari EOF dapat disesuaikan (dari file konfigurasi).

Saya akhirnya memindahkan semuanya ke python; sementara itu sedikit lebih lama, itu sedikit lebih efisien:

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()
Arcege
sumber
1

Anda dapat menambahkan ini ke skrip Anda untuk menerapkan jeda:

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

Itu menggunakan modul perl File :: Tail untuk berperilaku seperti tail -f logfile | grep Started SocketListener.

Ganti / var / log / pesan dengan file log yang sesuai. Perhatikan bahwa itu akan menggantung selamanya jika "Memulai SocketListener" tidak pernah muncul.

R Perrin
sumber
1

Mungkin Anda harus menggunakan batas waktu alih-alih menunggu tanpa batas waktu.

Fungsi bash di bawah ini akan memblokir hingga istilah pencarian yang diberikan muncul atau batas waktu yang diberikan tercapai.

Status keluar akan menjadi 0 jika string ditemukan dalam batas waktu.

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
}

Mungkin file log belum ada setelah meluncurkan Selenium. Dalam hal ini, Anda harus menunggu sampai muncul sebelum mencari string:

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))
}

Inilah cara Anda dapat menggunakannya:

wait_selenium_server "/var/log/selenium.log" 5m && \
echo -e "\n-------------------------- Selenium READY --------------------------\n"
Elifarley
sumber