`tail -f`直到看到文本


20

我有一台带有命令行界面的CI服务器,它允许我远程启动一项工作(jenkinsCI服务器和jenkins-cli.jar工具)。

在我开始工作后,我会tail -f看到日志(对不起,命令混乱):

ssh -t my-jenkins-host.com "tail -f \"/var/lib/jenkins/jobs/$job_name/builds/\`ls -ltr /var/lib/jenkins/jobs/$job_name/builds/ | grep '^l' | tail -n 1|awk '{print \$9}'\`/log\""

作业成功完成后,通常至少在5分钟后,我在输出中得到以下行:

Finished: SUCCESS

现在有什么好办法停止拖尾日志吗?即有没有像tail_until 'some line' my-file.log命令?

奖励:如果您可以提供答案,则匹配成功时返回0,匹配失败时返回1,并且您的解决方案在mac上有效,如果您能提供答案,则可以额外奖励!(我相信是基于bsd的)

Answers:


39

您可以通过管道tail -f输入sed,告诉它在看到要搜索的行时退出:

tail -f /path/to/file.log | sed '/^Finished: SUCCESS$/ q'

sed将默认输出其处理的每一行,并在看到该行后退出。tail当尝试写入下一行并看到其输出管道损坏时,该过程将停止


oh!完善。...因此,如果我匹配一件事(例如“成功”),是否有办法退出0,如果我匹配其他事物(例如“失败”),则有办法退出1?
aaronstacy'8

7
@aaronstacy如果您使用的是GNU grep,则该q命令将使用可选的退出代码。因此sed命令是sed '/^Finished: SUCCESS$/ q0; /^Finished: FAILURE$/ q1'
Michael Mrozek

6
如果这Finished: SUCCESS是输出的最后一行,这可能行不通
lk- 2012年

@Michael Mrozek aaaand当然我不是b / c我正在使用friggin mac
aaronstacy 2012年

1
该解决方案有一个主要缺陷:在我的情况下,日志以搜索到的行结尾。没有更多的行将被写,所以该过程将被卡住,因为尾巴没有断路:(
Phate

6
tail -f my-file.log | grep -qx "Finished: SUCCESS"

-q,表示安静,一旦找到匹配项即退出

-x品牌grep全系匹配

对于第二部分,请尝试

tail -f my-file.log | grep -m 1 "^Finished: " | grep -q "SUCCESS$"

-m <number>告诉grep在数字匹配后停止

grep -q退出状态将只0如果SUCCESS在该行的结尾处找到

如果要查看所有输出,则不能使用grep -q,但仍然可以

tail -f my-file.log | grep -m 1 "^Finished: "

除了FAILURE出现时,将退出状态设置为1会执行所有操作。


5
grep本来在回答中使用过,但是如果他正在使用tail -f,则可能要查看文件输出。grep不会显示所有中间线
Michael Mrozek

4

@Mikel的答案与@Mrozek的评论的变化形式(我会回复评论,但我认为我没有足够的特权)

tail -f my-file.log | tee >( grep -qx "Finished: SUCCESS" )

将允许您使用@Mikel的解决方案,并且仍然在屏幕上看到输出


我们是否可以为其添加超时间隔,例如:“如果在60到120秒之间未读取超时间隔,则终止尾部并在shell中给出错误退出代码”?
kiltek

2

我不喜欢这里的任何答案,因此决定自己提出。此bash脚本符合所有条件,并包括在失败时退出1的奖励。

#!/bin/bash
while IFS= read -r LOGLINE || [[ -n "$LOGLINE" ]]; do
    printf '%s\n' "$LOGLINE"
    [[ "${LOGLINE}" == "Finished: SUCCESS" ]] && exit 0
    [[ "${LOGLINE}" == "Finished: FAILURE" ]] && exit 1
done < <(timeout 300 tail -f my-file.log)
exit 3

还包括超时功能,该功能将导致退出代码为3。如果系统上没有超时命令,请从Anthony Thyssen获取timeout.sh脚本:

http://www.ict.griffith.edu.au/anthony/software/timeout.sh

根据下面的评论,我更新了日志打印以停止转义符扩展,并包括标准“读取”的所有功能。有关完整的“读取”详细信息,请参见/programming//a/10929511。这里不需要EOF检查,但是为了完整性起见,其中包含了EOF检查。


非常好。考虑使用while IFS= read -r LOGLINE来防止外壳程序在的行上进行空格分割tail
roaima

@roaima:read只有一个变量(并且不是带有的数组-a)时不会拆分,但是-r如果输入数据包含反斜杠,则需要这样做。但是,如果输入数据包含反斜杠,则echo "$var"视您的外壳和/或系统而定,也可能会搞砸,所以效果更好printf '%s\n' "$line"
dave_thompson_085

@ dave_thompson_085 了解“ IFS =读-r行”
roaima

0

这是一个几乎可以执行我想要的操作的python脚本(请参见以下警告):

import sys,re

def main():
    re_end = re.compile(sys.argv[1])
    re_fail = re.compile(sys.argv[2]) if len(sys.argv) > 2 else None
    for line in sys.stdin:
        sys.stdout.write(line)
        if re_end.match(line):
            sys.exit(0)
        elif re_fail and re_fail.match(line):
            sys.exit(1)

if __name__ == '__main__': main()

注意事项:

  • 线没有像进来一样被打印出来……它们是成组打印的……似乎有些缓冲

  • 我必须将其作为脚本安装在我的路径或其他东西上,所以不方便,而且我希望使用光滑的单线:)


更新:tail似乎做同样的缓冲,所以我猜这是不值得尝试的东西。
aaronstacy,2012年

0

我在sedgrep和他们的选项上遇到了问题,所以我写了我的one with bash conditions

tail -f screenlog.* | 
while IFS= read line; 
 do 
   echo $line; 
   if [[ $line == *Started\ Application* ]]; 
    then pkill tail; 
   fi; 
done

-1

你也试试

 grep -q 'App Started' <(tail -f /var/log/app/app.log)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.