2013-10-23 32 views
2

因此,我有一個bash命令來啓動一個服務器,它輸出一些行之前,它輸出的東西,如「服務器啓動,按Ctrl + C退出」。我如何管這個輸出,所以當這條線發生我把這個過程在後臺,並繼續與另一個腳本/功能(即做的東西,需要等到服務器啓動,如運行測試)將文本匹配後的管道進程推遲到後臺

我想結束了3個功能

  • START_SERVER
  • run_tests
  • STOP_SERVER

我沿着線得到的東西:

function read_server_output{ 
    while read data; do 
     printf "$data" 
     if [[ $data == "Server started, Press Control+C to exit" ]]; then 
      # do something here to put server process in the background 
      # so I can run another function 
     fi 
    done 
} 

function start_server{ 
    # start the server and pipe its output to another function to check its running 
    start-server-command | read_server_output 
} 

function run_test{ 
    # do some stuff 
} 

function stop_server{ 
    # stop the server 
} 

# run the bash script code 
start_server() 
run_tests() 
stop_tests() 

相關的問題可能SH/BASH - Scan a log file until some text occurs, then exit. How?

在此先感謝我很新了這一點。

回答

1

可能最容易做的事情是在後臺啓動它並阻止讀取其輸出。例如:

{ start-server-command & } | { 
    while read -r line; do 
    echo "$line" 
    echo "$line" | grep -q 'Server started' && break 
    done 
    cat & 
} 
echo script continues here after server outputs 'Server started' message 

但這是一個非常醜陋的黑客攻擊。如果可以修改服務器以執行腳本可以等待的更具體的動作,那將會更好。

+0

這應該工作過,並避免與我的方法輪詢問題。儘管隱藏服務器的輸出可能會更好,就像臨時文件方法一樣。 (但我認爲我們都同意,「最好」的方法是修復服務器:-)) – torek

+0

絕對修復服務器是正確的方法。正如你在答案中提到的那樣,緩衝也是一個問題,我可怕的黑客根本就沒有處理這個問題。 –

4

首先,關於術語的說明...

「背景」和「前景」被控制端的概念,即,他們與當你鍵入CTRL + CCTRL會發生什麼做+ Z等(哪個進程得到信號),進程是否可以從終端設備讀取(「後臺」進程得到默認使其停止的SIGTTIN)等等。

看起來很清楚,這與您想要達到的目標無關。相反,你有一個不適合的程序(或程序套件)需要一些特別的竅門:當服務器第一次啓動時,它需要一些手持到某個點,然後就可以了。一旦輸出一些文本字符串,手持可以停止(請參閱您的相關問題或下面的技術)。

這裏有一個很大的潛在的問題:很多程序,當其輸出重定向到一個管道或文件,產生沒有輸出,直到他們已經打印輸出的「塊」的價值,或者退出。如果是這種情況,一個簡單的:

start-server-command | cat 

不會打印您正在尋找的線(所以這是一個快速的方法來告訴你是否有解決這個問題,也是)。如果是這樣,你需要類似expect,這是一種完全不同的方式來實現你想要的。

儘管這並不是問題,但我們可以嘗試一種全面的方法。

你需要的是運行start-server-command並保存進程ID,這樣就可以(最終)發送一個SIGINT信號(如CTRL + C想,如果過程「在前臺」爲,但是你是通過腳本來完成這項工作的,而不是通過控制終端進行的,所以腳本沒有按鍵)。幸運的是sh僅僅爲此提供了一種語法。

首先,讓我們做一個臨時文件:

#! /bin/sh 
# myscript - script to run server, check for startup, then run tests 

TMPFILE=$(mktemp -t myscript) || exit 1 # create /tmp/myscript.<unique> 
trap "rm -f $TMPFILE" 0 1 2 3 15   # arrange to clean up when done 

現在啓動服務器,並保存其PID:

start-server-command > $TMPFILE &   # start server, save output in file 
SERVER_PID=$!        # and save its PID so we can end it 

trap "kill -INT $SERVER_PID; rm -f $TMPFILE" 0 1 2 3 15 # adjust cleanup 

現在,你想通過$TMPFILE掃描直到出現所需的輸出,在另一個問題。因爲這需要一定數量的輪詢,所以應該插入一個延遲。檢查服務器是否失敗並終止而沒有進入「開始」點也可能是明智之舉。

while ! grep '^Server started, Press Control+C to exit$' >/dev/null; do 
    # message has not yet appeared, is server still starting? 
    if kill -0 $SERVER_PID 2>/dev/null; then 
     # server is running; let's wait a bit and try grepping again 
     sleep 1 # or other delay interval 
    else 
     echo "ERROR: server terminated without starting properly" 1>&2 
     exit 1 
    fi 
done 

(這裏kill -0用於測試的過程中是否仍然存在;如果沒有,它已經退出了「清理」 kill -INT會產生錯誤信息,但是這可能OK如果沒有,要麼重定向kill命令的錯誤輸出,或者調整清理或手動執行,如下所示。)

此時,服務器正在運行,您可以執行測試。當你想讓它退出,就好像用戶點擊了ctrl + C,發送一個SIGINTkill -INT

由於有一個在trap集,用於當腳本退出kill -INT(0)時以及當它是由SIGHUP終止(1),SIGINT(2),SIGQUIT(3),和SIGTERM(15) - 這就是在:

trap "do some stuff" 0 1 2 3 15 

部分你可以簡單地讓你的腳本在此時退出,除非你要專門等待服務器退出了。如果你想,也許:

kill -INT $SERVER_PID; rm -f $TMPFILE # do the pre-arranged cleanup now 
trap - 0 1 2 3 15      # don't need it arranged anymore 
wait $SERVER_PID      # wait for server to finish exit 

將是適當的。

(顯然沒有上面的測試,但是這是總體框架。)