2010-04-22 50 views
2

我有一個在unix下運行的程序(我無法控制)在完成時打印'成功完成'但未退出。我想自動檢測進程何時結束(通過檢查命令的輸出),以便我可以終止進程,以便我可以繼續執行其他活動。複雜性是因爲我想能夠同時運行多個這些腳本。 (我需要做的一項活動需要用各種輸入調用腳本,但每次腳本運行需要一段時間才能返回,因此我想並行執行它們)檢測進程何時完成(但未退出)

有沒有人做過類似於這個? 我可以將該命令的stderr和stdout輸出重定向到一個具有隨機文件名的臨時文件,然後將文件和管道尾部尾部條件(即某些日誌行)以grep結尾。問題是,當然tail -f會繼續運行,所以它永遠不會退出。我應該輪詢嗎?如果是這樣,最好的方法是什麼?

+0

不幸的是,我在舊的Solaris mac上運行有bash 2.x的hine;沒有指望;它看起來像我沒有grep --max-count = 1 – Egwor 2010-04-26 19:49:40

回答

2

#在/ usr/bin中/期望

spawn/home/foo/myjob
預計「成功完成」

+0

我不認爲這實際上會殺死這個進程,我相信在發送SIGHUP之後等待所有派生進程完成。我收集到的問題是,這是一個行爲不當的程序,所以SIGHUP可能不會做很多... 儘管人們當然可以抓取spawn返回的PID,並在期望後運行exec kill。 – wich 2010-04-23 14:05:46

+0

@wich即使這是真的,這個過程也不得不離開它來處理嘆息。但是,當然,你可以明確地發送你喜歡的任何信號。我只是認爲期待處理等待「成功完成」像我能想到的任何方法一樣優雅。 – frankc 2010-04-23 14:21:01

2

您不必投票。您可以使用inotify工具(如inotifywait)檢測輸出文件何時發生更改,然後grep並在必要時終止進程。快樂狩獵!

+0

這看起來很有趣。不幸的是我在一臺舊的Solaris機器上運行:( – Egwor 2010-04-22 20:12:45

0

這可能是矯枉過正的bash,也許?如果您使用python,則可以使用subprocess模塊在自己的程序和子腳本之間保持通信通道的打開狀態。更好的是,您可以使用threading模塊並行地啓動多個子腳本的運行。

該腳本輸出任何東西后,它輸出「成功完成」?如果沒有,你可以輪詢它輸出的最後x個字符(像你建議的一個隨機文件,也許使用tail -n 1得到最後一行),看看你是否看到'成功完成'。但如果腳本後繼續打印內容,則可能會錯過該行。

或者你可以在grep中輸出「已成功完成」。

0

一些隨機的想法。 (1)如果它是你的程序,你可以修改它以更有用地指示完成。 (2)查看進程列表(ps ax),當它嘗試輸出「已完成」消息時,應該能夠看到它進入I/O等待狀態。 (3)我相信僞tty的存在是爲了這個目的,你可以直接觀看他們的標準輸出,而不必沉迷於臨時文件。

0

第一可能的解決方案:
your_program> tempfile1
的grep -i 「成功完成」 tempfile1;如果[$? -eq 0];那麼我=`pidof your_program`;殺死我; fi

首先是重定向。其次檢查grep的退出狀態。如果它是0(成功),它將獲得程序的pid並殺死它。
這是一個「思維敏捷」練習。它應該工作。缺點是你一次只能運行你的程序的一個實例,但是當然可以進行修改並且你可以並行運行它。

編輯27.05.2010:
第二可能的解決方案:
尾--pid =`的pidof your_program` -f -n0 tempfile1 | awk'/ Completed/{if($ 1 ==「Completed」){system(「i =`pidof your_program`; kill $ i」)}}'&

那麼,需要一個循環/ crontab了。說明:
--pid =`pidof your_program`在指定的PID結束後使尾部死亡。這樣,當程序被殺時,尾隨它一起死亡。
-n0忽略tempfile1中的其他「Completed」語句(因此,您不必擔心總是首先截斷tempfile1)。
awk搜索程序拋出的「Completed」語句,{system}部分執行程序中的kill。
也不要忘記&最後,因爲它背景的整個事情。
玩得開心。

+0

將代碼縮進四個空格,然後將其格式化爲代碼塊,以保留縮進和換行符 – wich 2010-04-22 09:46:52

+0

雖然我需要做一個循環,對吧?那麼如果'成功完成'幾分鐘沒有到達,那麼grep就會失敗,但我喜歡你的概念,因爲我似乎對我的可用流程相當有限。 – Egwor 2010-04-26 19:51:20

+0

是的,一個循環,或者只需在每分鐘添加它在crontab中 我也想出了另一個解決方案(我已經編輯了我的主要文章,因爲我無法在註釋中對代碼進行格式化) – w00t 2010-05-27 08:57:49

1

這是我的刺,它工作得很好,但是相當垃圾,因爲每次kill被稱爲一個殺死的消息,回聲整個subhell腳本輸出到控制檯,我似乎無法抑制它。我會更新,如果我找到一種方法來擺脫垃圾郵件,(順便說一下,重定向stdout和stderr到/ dev/null沒有幫助。)

注意:您需要bash4來運行此; $BASHPID只能從4開始提供,並且$$不是替代方案,因爲它提供了父shell的pid,而不是子shell。

!/bin/bash 

for i in {1..8}; do 
    (
    mypid=$BASHPID 
    (
     #subshell to simulate started process 
     sleep 2 
     echo finished 
     while : ; do 
     : 
     done 
    ) | \ 
    { 
     while read line; do 
     if [[ $line == finished ]]; then 
      break; 
     fi 
     done 
     echo process done, killing $mypid... 
     kill -9 $mypid 
    } 
) & 
done 
wait 
1

以下包裝器腳本會打電話給你真正的命令,管道輸出到發球這將寫入FIFO。這個腳本會殺了你的真實的命令,當預期字符串greped從FIFO:

#!/bin/bash 

# cmd to run 
expected_output=$1 
shift 
cmd=("[email protected]") 
# where to read commands output 
mkfifo /tmp/killonoutput.$$ 
# start cmd async 
"${cmd[@]}"|tee /tmp/killonoutput.$$ 2>/dev/null & 

if grep -q --max-count=1 "$expected_output" /tmp/killonoutput.$$;then 
    kill %1 
    echo "Killed ${cmd[@]}" 
fi 
# grep returned so fifo was closed 
rm /tmp/killonoutput.$$ 

樣品執行:

./killonoutput.sh "Finished" bash -c "echo sleeping;sleep 3;echo Finished; sleep 10000" 
sleeping 
Finished 
Killed bash -c echo sleeping;sleep 3;echo Finished; sleep 10000 
./killonoutput.sh: line 17: 19553 Terminated    "${cmd[@]}" 
    19554      | tee /tmp/killonoutput.$$ 2> /dev/null