2011-08-18 58 views
1

我有一個腳本,我的意思是從cron運行,確保我寫的守護進程正在工作。該腳本文件的內容類似於以下內容:爲什麼在腳本中使用反引號執行的命令會給我不同的結果?

daemon_pid=`ps -A | grep -c fsdaemon` 
echo "daemon_pid: " $daemon_pid 
if [ $daemon_pid -eq 0 ]; then 
    echo "restarting fsdaemon" 
    /etc/init.d/fsdaemon start 
fi 

當我從命令提示符下執行這個腳本,呼應的$ daemon_pid值報告爲2的值,該值是二不管線路我的守護進程是否在運行。但是,如果我用反引號執行該命令,然後檢查$ daemon_pid變量,那麼$ daemon_pid的值現在爲1。我也嘗試過使用bashdb單步執行腳本,當我使用該工具檢查變量時,他們應該是。

因此,我的問題是:爲什麼在shell執行腳本時與手動執行腳本中的命令之間存在行爲差異?我敢肯定,我缺少一些非常重要的東西。

+2

只是爲了檢查顯而易見的:腳本文件的名稱不包含'fsdaemon',是嗎? –

+0

事實上,腳本文件的名稱是「check-fsdaemon」。這也許是一個重要的原因(我看到兩個)。另一個來自命令行的grep? –

+0

另外,'grep'進程的參數列表中有'fsdaemon'。你可以不用'-c'來驗證它。 –

回答

3

您很可能會遇到grep作爲ps的「答案」的一部分。

爲了幫助完全理解正在發生的事情,請關閉-c選項,以查看僅從ps -A | grep fsdameon返回的數據。

爲了解決這個問題,一些系統有一個p(rocess)grep(pgrep)。這將工作,或

ps -A | grep -v grep | grep -c fsdaemon 

是一個常見的習慣用法,你會看到,但在犧牲另一個進程。

的乾淨的解決方案是,

ps -A | grep -c '[f]sdaemon' 

的正則表達式語法應與所有工作裏grep,在所有系統上。

我希望這會有所幫助。

+0

我真的很喜歡pgrep命令,它在debian 5下支持。謝謝。 –

+0

根據我的測試,似乎'grep'找到反引號產生的子進程 - 它實際上並沒有發現它自己,因爲'ps -A'沒有列出命令行參數。 –

+0

感謝您的洞察力。我通常使用'ps -ef'或'ps auexww',但將'ps -A'留作我答案的一部分,因爲這是OP的用法。祝你們好運。 – shellter

3

問題是grep的本身就說明了...嘗試grep的-c後運行與任何命令:

eple:~ erik$ ps -a | grep -c asdfladsf 
1 
eple:~ erik$ ps -a | grep -c gooblygoolbygookeydookey 
1 
eple:~ erik$ 

什麼ps -a | grep fsdaemon回報?只要看看實際列出的進程... :)

1

包含該名稱的參數的aany進程將添加到計數 - grep和您的腳本。

ps ing for a process is not really reliable,you should use a lock file。

2

既然這是Linux,爲什麼不試試pgrep?這爲您節省了一個管道,並且您不會以grep報告守護進程腳本本身的運行結束。

0

由於有幾個人已經指出,因爲ps | grep檢測到(1)腳本本身和(2)反引號創建的子進程,它繼承了主腳本的名稱,所以您的進程數量被誇大了。所以一個簡單的解決方案是將腳本的名稱更改爲不包含您要查找的名稱的名稱。但你可以做得更好。

我建議的「最佳實踐」解決方案是使用操作系統提供的工具。初始化腳本創建一個PID文件作爲啓動守護進程的一部分並不罕見;換句話說,不是隻運行守護進程本身,而是使用啓動守護進程的包裝腳本,然後將進程ID寫入某個文件中。如果不存在您的系統上start-stop-daemon(我認爲這是這些天很常見),你可以使用像這樣:

start-stop-daemon --start --quiet --background \ 
    --make-pidfile --pidfile /var/run/fsdaemon.pid -- /usr/bin/fsdaemon 

(顯然取代路徑/usr/bin/fsdaemon如適用)來啓動它,然後

start-stop-daemon --stop --quiet --pidfile /var/run/fsdaemon.pid 

停止它。 start-stop-daemon還有其他可能對您有用的選項,您可以通過閱讀手冊頁進行調查。

如果您沒有訪問start-stop-daemon,你可以寫一個包裝腳本來執行基本相同的事情,像這樣開始:

echo "$$" > /var/run/fsdaemon.pid 
exec /usr/bin/fsdaemon 

,這阻止:

kill $(< /var/run/fsdaemon/pid) 
rm /var/run/fsdaemon.pid 

(當然這很粗糙,但它通常應該可以正常工作)。

無論如何,一旦你的設置來生成一個PID文件,是否使用start-stop-daemon與否,你可以更新你的check腳本來此:

daemon_pid=`ps --no-headers --pid $(< /var/run/fsdaemon.pid) | wc -l` 
if [ $daemon_pid -eq 0 ]; then 
    echo "restarting fsdaemon" 
    /etc/init.d/fsdaemon restart 
fi 

(人會想到會有簡短的命令檢查給定的PID是否正在運行,但我不知道它)。

如果你不想(或不能)創建一個PID文件,我至少會建議pgrep代替ps | grep,因爲pgrep將名義直接搜索的過程,並不會發現任何東西,只是恰好包含相同的字符串。

daemon_pid=`pgrep -x -c fsdaemon` 
if [ $daemon_pid -eq 0 ]; then 
    echo "restarting fsdaemon" 
    /etc/init.d/fsdaemon restart 
fi 

-x手段 「嚴絲合縫」,並-c作品與grep

順便說一下,當它實際上是一個計數時,命名變量daemon_pid似乎有點誤導。

相關問題