テキストが表示されるまでの `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コマンドのようなものはありますか?

ボーナス: SUCCESSが一致した場合に0、FAILUREが一致した場合に1を返し、ソリューションがMacで機能する場合に返される回答を提供できる場合の追加クレジット。(これはbsdベースだと思います)

回答:


39

をパイプしtail -fsed、検索している行が見つかったら終了するように指示できます。

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

sedデフォルトで処理する各行を出力し、その行を見た後に終了します。tailそれは次の行を記述しようとすると、その出力パイプが壊れている見ていると、プロセスが停止します


うん!完璧です。...だから、万が一何かに一致した場合(「成功」など)に0を終了し、他の何か(「失敗」など)に一致した場合に1を終了する方法はありますか?
aaronstacy

7
@aaronstacy GNU grepを使用している場合、qコマンドはオプションの終了コードを受け取ります。したがって、sedコマンドは次のようになりますsed '/^Finished: SUCCESS$/ q0; /^Finished: FAILURE$/ q1'
Michael Mrozek

6
このかもしれないではない作品の場合は、Finished: SUCCESS出力の最後の行である
lk-

@Michael Mrozekはaaaandもちろん私はB /私はfrigginのマックを使用していますcはいないよ
aaronstacy

1
このソリューションには重大な欠陥があります。私の場合、ログは検索された行で終了します。これ以上行は書き込まれないので、テールにはブレークする方法がないため、プロセスは
停止したままになります。

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

-q、つまり「静か」は、一致するものが見つかるとすぐに終了します

-x作るには、grep行全体にマッチ

2番目の部分については、試してください

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

表示される場合、終了ステータスを1に設定する以外のすべてを実行しFAILUREます。


5
私はgrepもともと私の回答で使用しましたが、彼が使用している場合tail -f、おそらくファイルの出力を見たいと思っています。grepすべての中間行を表示するわけではありません
Michael Mrozek

4

@Mrozekのコメント付きの@Mikelの回答のバリエーション(コメントに返信しますが、まだ十分な権限がないと思います)

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

@Mikelのソリューションを使用しても、画面に出力を表示できます


「60秒から120秒の間に読み取られない場合、テールを中止して、シェルでエラー終了コードを返す」などのタイムアウト間隔を追加できますか?
キルテック

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

以下のコメントに従って、ログプリントを更新してエスケープ文字の展開を停止し、標準の「読み取り」のすべての機能を含めました。完全な「読み取り」の詳細については、https://stackoverflow.com/a/10929511を参照してください。EOFチェックはここでは必要ありませんが、完全を期すために含まれています。


非常に素晴らしい。while IFS= read -r LOGLINEからの行で空白分割を実行するシェルを防ぐために使用することを検討してくださいtail
ロアイマ

@roaima:read変数が1つしかない場合(およびの配列ではない場合)は分割されません-a-r、入力データにバックスラッシュが含まれる場合は必要です。入力されたデータは、バックスラッシュが含まれている場合しかし、その後echo "$var"もそう良く、自分の殻および/またはシステムに応じて、台無しにするprintf '%s\n' "$line"
dave_thompson_085


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

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.