bash 结束 tail -f 在 shell 脚本中启动
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2041437/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Ending tail -f started in a shell script
提问by rangalo
I have the following.
我有以下内容。
- A Java process writing logs to the stdout
- A shell script starting the Java process
- Another shell script which executes the previous one and redirects the log
- I check the log file with the
tail -f
command for the success message.
- 将日志写入标准输出的 Java 进程
- 启动 Java 进程的 shell 脚本
- 另一个执行前一个脚本并重定向日志的 shell 脚本
- 我使用
tail -f
成功消息的命令检查日志文件。
Even if I have exit 0 in the code I cannot end the tail -f
process.
即使我在代码中有 exit 0 我也不能结束这个tail -f
过程。
Which doesn't let my script to finish. Is there any other way of doing this in Bash?
这不会让我的脚本完成。在 Bash 中还有其他方法可以做到这一点吗?
The code looks like the following.
代码如下所示。
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
}
采纳答案by falstro
The best answer I can come up with is this
我能想出的最佳答案是这个
- Put a timeout on the read,
tail -f logfile | read -t 30 line
- Start tail with
--pid=$$
, that way it'll exit when the bash-process has finished.
- 在读取上设置超时,
tail -f logfile | read -t 30 line
- 以 开头
--pid=$$
,这样它会在 bash 进程完成时退出。
It'll cover all cases I can think of (server hangs with no output, server exits, server starts correctly).
它将涵盖我能想到的所有情况(服务器挂起没有输出,服务器退出,服务器正确启动)。
Dont forget to start your tail before the server.
不要忘记在服务器之前启动你的尾巴。
tail -n0 -F logfile 2>/dev/null | while read -t 30 line
the -F
will 'read' the file even if it doesn't exist (start reading it when it appears). The -n0
won't read anything already in the file, so you can keep appending to the logfile instead of overwriting it each time, and to standard log rotation on it.
在-F
将“读”,即使它不存在的文件(开始读它出现时)。该-n0
文件将没有读什么,这样你就可以继续追加到日志文件,而不是每次都覆盖它,并且标准的日志旋转就可以了。
EDIT:
Ok, so a rather crude 'solution', if you're using tail. There are probably better solutions using something else but tail, but I got to give it to you, tail gets you out of the broken-pipe quite nicely. A 'tee' which is able to handle SIGPIPE would probably work better. The java process actively doing a file system drop with an 'im alive' message of some sort is probably even easier to wait for.
编辑:
好的,如果您使用tail,那么这是一个相当粗糙的“解决方案”。除了使用 tail 之外,可能还有更好的解决方案,但是我必须将其提供给您,tail 可以很好地让您摆脱断管。能够处理 SIGPIPE 的“三通”可能会更好。使用某种“我还活着”消息主动执行文件系统删除的 java 进程可能更容易等待。
function startServer() {
touch logfile
# 30 second timeout.
sleep 30 &
timerPid=$!
tail -n0 -F --pid=$timerPid logfile | while read line
do
if echo $line | grep -q 'Started'; then
echo 'Server Started'
# stop the timer..
kill $timerPid
fi
done &
startJavaprocess > logfile &
# wait for the timer to expire (or be killed)
wait %sleep
}
回答by Robert Christie
According to the tail man page, you can get tail to terminate after the a process dies
根据tail手册页,您可以在进程终止后使tail终止。
In BASH, you can get the PID of the last started background process using $! SO if you're using bash:
在 BASH 中,您可以使用 $! 所以如果你使用 bash:
tail -f --pid=$! logfile
回答by David Resnick
Based on the answers I found here, this is what I've come up with.
根据我在这里找到的答案,这就是我想出的。
It directly deals with tail and kills it once we've seen the needed log output. Using 'pkill -P $$ tail' should ensure that the right process is killed.
它直接处理 tail 并在我们看到所需的日志输出后将其杀死。使用 'pkill -P $$ tail' 应该确保正确的进程被杀死。
wait_until_started() {
echo Waiting until server is started
regex='Started'
tail logfile -n0 -F | while read line; do
if [[ $line =~ $regex ]]; then
pkill -9 -P $$ tail
fi
done
echo Server is started
}
回答by Alberto Zaccagni
Capture the pid of the background process
捕获后台进程的pid
pid=$!
Use tail's --pid=PIDoption, so that it terminates after the process having pid $PID terminates.
使用 tail 的--pid=PID选项,以便它在具有 pid $PID 的进程终止后终止。
回答by user985216
I have had a similar situation where I need to tail a log for a "started" message within a reasonable time and if it is not found during that time I need to exit. Here is what I ended up doing.
我遇到过类似的情况,我需要在合理的时间内为“开始”消息拖尾日志,如果在那段时间内没有找到它,我需要退出。这是我最终做的。
wait_tomcat_start(){
WAIT=60
echo "Waiting for Tomcat to initialize for $WAIT seconds"
# Tail log file, do a while read loop with a timeout that checks for desired log status,
# if found kill the find and break the loop. If not found within timeout: the read -t will
# kill the while read loop and bounce to the OR statement that will in turn kill the tail
# and echo some message to the console.
tail -n0 -f $SERVERLOG | while read -t $WAIT LINE || (pkill -f "tail -n0 -f" && echo "Tomcat did not start in a timely fashion! Please check status of tomcat!!!")
do
echo "$LINE"
[[ "${LINE}" == *"Server startup in"* ]] && pkill -f "tail -n0 -f" && break
done
}
I'm not sure this is very elegant or even the best way to do it, but it works good enough for me. I'd be happy for any opinions :)
我不确定这是否非常优雅,甚至是最好的方法,但它对我来说已经足够好了。我很高兴有任何意见:)
回答by CondorEye
Had a similar issue where the tail process wasnt getting killed when
有一个类似的问题,当尾部进程没有被杀死时
- Run through jsch
- tail wasnt producing any output to jsch and hence to its output stream.
- 通过jsch运行
- tail 没有向 jsch 产生任何输出,因此也没有产生任何输出到它的输出流。
Used the --pid=$!
to kill it and started a infinite while loop to echo something in the background before the tail which gets killed when the underlying process is killed and thus kills the tail.
使用 the--pid=$!
来杀死它并开始一个无限的 while 循环,以在尾部之前在后台回显某些东西,当底层进程被杀死时,尾部会被杀死,从而杀死尾部。
( while true; do echo 'running'; sleep 5; done ) & ( tail -f --pid=$! log-file )
回答by Flimm
How about using an infinite loop instead of the -f command-line option for tail?
如何使用无限循环而不是 -f 命令行选项用于 tail ?
function startServer() {
startJavaprocess > logfile &
while [ 1 ]
do
if tail logfile | grep -q 'Started'; then
echo 'Server started'
exit 0
fi
done
}
回答by paxdiablo
Rather than exiting the process, you can instead find the process ID of the tail -f
process and kill it (a kill -9
would even be safe here if you're sure the log file has finished).
与其退出进程,您还可以找到进程的进程 IDtail -f
并杀死它(kill -9
如果您确定日志文件已完成,这里甚至是安全的)。
That way, the while read line
will terminate naturally and you won't need to exit.
这样,while read line
意志自然终止,您将不需要退出。
Or, since you're not really using the tail
to output to the screen, you could also try the more old-school:
或者,由于您并没有真正使用tail
to 输出到屏幕,您也可以尝试更老派的:
grep -q 'Started' logfile
while [[ $? -ne 0 ]] ; do
sleep 1
grep -q 'Started' logfile
done
回答by user1008204
I had the same problem, couldn't find simple and good solution. I'm not good in Python, but I managed somehow to solve this:
我遇到了同样的问题,找不到简单而好的解决方案。我不擅长 Python,但我设法解决了这个问题:
wait_log.py:
等待日志.py:
#!/usr/bin/env python
from optparse import OptionParser
import os
import subprocess
import time
def follow(file):
def file_size(file):
return os.fstat(file.fileno())[6]
def is_newLine(line):
return line != None and line.find("\n") != -1;
file.seek(0, os.SEEK_END)
while True:
if file.tell() > file_size(file):
file.seek(0, os.SEEK_END)
line_start = file.tell()
line = file.readline()
if is_newLine(line):
yield line
else:
time.sleep(0.5)
file.seek(line_start)
def wait(file_path, message):
with open(file_path) as file:
for line in follow(file):
if line.find(message) != -1:
break
def main():
parser = OptionParser(description="Wait for a specific message in log file.", usage="%prog [options] message")
parser.add_option("-f", "--file", help="log file")
(options, args) = parser.parse_args()
if len(args) != 1:
parser.error("message not provided")
if options.file == None:
parser.error("file not provided")
wait(options.file, args[0])
if __name__ == "__main__":
main()
回答by nurro
It is possible to background tail -f logfile
, send tailpid
to the while read
loop subshell and implement a trap
on EXIT to kill the tail
command.
可以后台tail -f logfile
,发送tailpid
到while read
循环子shell并trap
在 EXIT 上实现一个来终止tail
命令。
( (sleep 1; exec tail -f logfile) & echo $! ; wait) | (
trap 'trap - EXIT; kill "$tailpid"; exit' EXIT
tailpid="$(head -1)"
while read line
do
if echo $line | grep -q 'Started'; then
echo 'Server Started'
exit 0
fi
done
)