簡體   English   中英

在子shell中使用tail和while / break不會退出循環

[英]Using tail in a subshell in conjunction with while/break does not exit the loop

我一直面臨着shell腳本的一個非常奇怪的問題。

這是場景

Script1(在后台生成) - > Script2

Script2具有以下代碼

function check_log()
{
    logfile=$1
    tail -5f ${logfile} | while read line
    do
      echo $line
      if echo $line|grep "${triggerword}";then
        echo "Logout completion detected"
        start_leaks_detection
        triggerwordfound=true
        echo "Leaks detection complete"
      fi
      if $triggerwordfound;then
        echo "Trigger word found and processing complete.Exiting"
        break
      fi

    done
        echo "Outside loop"
        exit 0

}

check_log "/tmp/somefile.log" "Logout detected"

現在,while循環中斷並沒有幫助。 我可以看到“檢測到注銷完成”以及“泄漏檢測完成”在標准輸出上回顯,但不是字符串“外部循環”

我假設這必須用tail -f創建一個子shell。 我想要做的是,退出子shell並退出Script2以控制回Script1。

有人可以說明如何做到這一點嗎?

而不是管道進入你的while循環,而是使用這種格式:

while read line
do
   # put loop body here
done < <(tail -5f ${logfile})

試試這個,雖然它不完全相同(它不會在啟動時跳過日志文件的開頭):

triggerwordfound=
while [ -z "$triggerwordfound" ]; do
    while read line; do
        echo $line
        if echo $line|grep "${triggerword}";then
            echo "Logout completion detected"
            start_leaks_detection
            triggerwordfound=true
            echo "Leaks detection complete"
        fi
    done
done < "$logfile"
echo "Outside loop"

雙循環有效地與tail -f做同樣的事情。

從某種意義上說,您的函數是有效的,但是在找到觸發器字之后,在將另一行寫入文件之前,您不會注意到它。 這是因為tail -5 -f通常可以在一次write()調用中將文件的最后五行write()管道並繼續在一次調用中寫入新行,因此直到它才會發送SIGPIPE信號直到它會在while循環退出嘗試寫入管道。

因此,如果您的文件經常增長,那么應該沒有問題,但如果您的文件在寫入觸發器字后立即停止增長更常見,那么您的觀察器腳本也會掛起,直到寫入任何新輸出到文件。

即管道關閉時,即使在其中緩存了未讀取的數據,也不會立即發送SIGPIPE ,但僅在嘗試管道上的后續write()時才發送。

這可以非常簡單地證明。 此命令不會退出(假設文件的尾部小於管道大小的緩沖區),直到您手動中斷它,或者再向文件寫入一個字節:

tail -f some_large_file | read one

但是,如果強制tail對管道進行多次寫入並確保讀取器在最終寫入之前退出,那么一切都將按預期工作:

tail -c 1000000 some_large_file | read one

不幸的是,在給定系統上發現管道緩沖區的大小並不總是很容易,也不總是只能在文件中已經存在多個管道緩沖區的數據時才開始讀取文件,並且觸發字已經是在文件中,至少是文件末尾的管道緩沖區大小字節。

不幸的是, tail -F (你應該使用它而不是-f )也不會嘗試每5秒寫一個零字節,否則這可能會以更有效的方式解決你的問題。

此外,如果您要堅持使用tail ,那么-1可能就足夠了,至少對於檢測任何未來事件而言。

順便說一句,這是一個稍微改進的實現,仍然使用tail因為我認為這可能是你最好的選擇(你總是可以用cron或類似的方法在日志中添加一個周期標記行(大多數syslogd實現也有內置的標記功能)來保證您的函數將在標記期間返回:

check_log ()
{
        tail -1 -F "$1" | while read line; do
                case "$line" in
                *"${2:-SOMETHING_IMPOSSIBLE_THAT_CANNOT_MATCH}"*)
                        echo "Found trigger word"
                        break
                        ;;
                esac
        done
}

echo語句替換為讀取觸發器短語時需要執行的任何處理。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM