Завершение хвоста -f началось в сценарии оболочки - PullRequest
25 голосов
/ 11 января 2010

У меня есть следующее.

  1. Процесс Java записывает логи в стандартный вывод
  2. Сценарий оболочки, запускающий процесс Java
  3. Еще один сценарий оболочки, который выполняет предыдущий и перенаправляет журнал
  4. Я проверяю файл журнала с помощью команды tail -f для сообщения об успехе.

Даже если у меня есть выход 0 в коде, я не могу завершить процесс tail -f.

Что не позволяет моему сценарию завершиться. Есть ли другой способ сделать это в Bash?

Код выглядит следующим образом.

function startServer() {
  touch logfile
  startJavaprocess > logfile &

  tail -f logfile | while read line 
  do
    if echo $line | grep -q 'Started'; then
      echo 'Server Started'
      exit 0
    fi
  done
}

Ответы [ 18 ]

0 голосов
/ 28 августа 2018

Выполнить предыдущую команду с nohup.

В моем случае, запустите java -jar с nohup, например

nohup java -jar trade.jar xx.jar &

не будет выводиться журнал, но будет создан новый «nohup.out». Оригинальный лог-файл trade.log тоже работает.

Затем, tail -f trade.log, оболочка покажет информацию журнала, Ctrl-c может прервать ее, вернуться в оболочку.

0 голосов
/ 21 апреля 2017
tail -n0 --pid=$(($BASHPID+1)) -F logfile | sed -n '/Started/{s/.*/Server Started/p; q}'

При конвейерной обработке PID являются последовательными, поэтому pid хвоста будет $ BASHPID, а pid sed будет $ BASHPID + 1. Ключ --pid приведет к выходу tail (правильно!) При выходе из команды sed. Эта команда sed ищет / Started /, а затем заменяет всю строку (. *) На «Server Started», а затем завершает работу.

0 голосов
/ 22 марта 2016

Используя комбинацию ответов, я придумал это простое решение. В этом примере вызывается скрипт startup.sh Tomcat, а затем подключается журнал catalina.out до тех пор, пока не регистрируется «Запуск сервера», а затем он перестает подключаться.

#!/bin/bash

function logUntilStarted() {
    tail -n0 -F /home/tomcat/logs/catalina.out | while read line; do
        if echo $line && echo $line | grep -q 'Server startup' ; then
            pkill -9 -P $$ tail > /dev/null 2>&1
        fi
    done
}

/home/tomcat/bin/startup.sh
logUntilStarted
0 голосов
/ 03 декабря 2013

Мое предпочтительное решение этой проблемы - поместить команду tail и ее потребителя в подоболочку и позволить логике фильтра уничтожить родителя и его дочерних элементов (который включает в себя процесс tail). Если вы посмотрите на дерево процессов, оно будет:

startServer (pid=101)
   startServer (pid=102) << This is the subshell created by using parens "(...)"
      tail -f logfile (pid=103) << Here's the tail process
      startServer (pid=104)     << Here's the logic that detects the end-marker

В этом подходе логика определения конечного маркера (pid 104) ищет свой родительский PID (102) и все его дочерние элементы и убивает весь пакет, включая самого себя. Тогда дедушка (pid 101 выше) может продолжить.

function startServer() {
  touch logfile
  startJavaprocess > logfile &

  tail -f logfile | while read line 
  do
    if echo $line | grep -q 'Started'; then
      echo 'Server Started'
      mypid=$BASHPID
      pipeParent=$(awk '/^PPid/ {print $2}' /proc/$mypid/status)
      kill -TERM $pipeParent $(pgrep -P $pipeParent)  # Kill the subshell and kids
    fi
  done
}

# To invoke startServer(), add a set of parens -- that puts it in a subshell:
(startServer())
0 голосов
/ 11 января 2010

Не используйте tail - вы можете получить тот же «монитор самой новой вещи в файле», используя read.

Здесь я использую FIFO вместо файла журнала:

function startServer() {
  mkfifo logfile
  startJavaprocess > logfile &

  a=""; while [ "$a" != "Started" ]; do read <logfile a; done

  echo "Server Started"
}

Обратите внимание, что это приводит к зависанию FIFO.

0 голосов
/ 12 июля 2012

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

Используя режим отладки bash, я вижу, что команда выхода была вызванано процесс все еще зависал, пока еще одна строка не сбрасывалась в файл журнала сразу после 'Started'.Самое странное, что когда вышло сообщение «Запущено», даже был вызван выход, процесс все равно чем-то зацепился.Я предполагаю, что это было tail -f, пока не появится еще одна строка, это действительно освободит крючок.

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

0 голосов
/ 12 января 2010

Это должно сработать, и хвост должен умереть, как только умирает субоболочка

<code>
function startServer() {
  touch logfile
  startJavaprocess &gt logfile &

  while read line 
  do
    if echo $line | grep -q 'Started'; then
      echo 'Server Started'
      exit 0
    fi
  done &lt &lt(tail -f logfile)
}

Попробуйте это:

function startServer() {
  while read line 
  do
    if echo $line | grep -q 'Started'; then
      echo 'Server Started'
      return 0
    fi
  done &lt &lt(startJavaprocess | tee logfile)
}
</code>
0 голосов
/ 28 июня 2011

Использование tail -n0 -f, переданного по каналу grep, действительно является хорошим решением, и действительно, первый процесс в конвейере умрет, когда попытается вывести его в мертвый процесс grep.

Но если выища текст, который появляется рядом с последним текущим выводом хвоста, тогда grep уже прочитает весь ввод из хвоста (в одном блоке), и, следовательно, больше не будет текстового вывода в журнале, который нужно отправить внизканал как grep уже прочитал его перед выходом (или, может быть, он уже находился в буфере канала) - по крайней мере, это мое понимание.

Использование параметра -m1 в grep выглядит так, как будто он работает точночто вы хотите, и оставьте ввод сразу после соответствующей строки, но, похоже, это не имело значения или помогло мне в поиске аналогичной функциональности.Я подозреваю, что буферный канал все еще хранит весь текст, выводимый из tail, или по какой-то другой причине для tail не осталось ничего для вывода.Вы хотели, чтобы этот текст после grep-match все еще оставался для вывода следующим, потому что это то, что убило бы ваш хвост, когда он попытался (все еще рискованно - что произойдет, если его последняя строка по какой-то причине?), И вернуло управление вызывающему скрипту.

Я нашел способ обойти это - вывести что-либо в конец файла журнала, когда grep завершит работу;то есть.

tail -f logfile |(grep -q; echo >> logfile)

У меня есть теория, что (если мое предположение верно), вы можете заставить канал меньше буферизоваться, чтобы он работал без этого, или, возможно, добавив huponexitустановка команды для соответствующего компонента канала - т.е. в (возможно, фигурных) скобках поможет;но я не заботился о добавлении пустой строки в файл журнала, и он работал нормально, и это всего лишь меньший тестовый скрипт (так что это не долговечный файл журнала, который должен придерживаться формата для другой обработки).

shopt -s huponexit был бы полезен, но для его недолговечности.

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

...