2013-12-13 34 views
2

這裏是一個失敗bash腳本預期文檔未表現

#!/bin/tcsh 

#here is some code in tcsh I did not write which spawns many processes. 
#let us pretend that it spawns 100 instances of stupid_test which the user kills 
#manually after an indeterminate period 

/bin/bash <<EOF 
#!/bin/bash 
while true 
do 
if [[ `ps -e | grep stupid_test | wc -l` -gt 0 ]] 
then 
    echo 'test program is still running' 
    echo `ps -e | grep stupid_test | wc -l` 
    sleep 10 
else 
    break 
fi 
done 
EOF 

echo 'test program finished' 

的stupid_test程序是由

#!/bin/bash 
while true; do sleep 10; done 

預期的行爲是運行直到stupid_test被殺死的最小測試用例(在這種情況下由用戶手動),然後在接下來的十秒內終止。觀察到的行爲是腳本不會終止,並且即使在程序被終止之後也評估爲ps -e | grep stupid_test | wc -l == 1(並且它不再顯示在ps下)

如果bash腳本直接運行而不是在這裏文件,預期的行爲被恢復。

我覺得自己在做一些非常愚蠢的錯事,我根本不是最有經驗的shell黑客。它爲什麼這樣做?

+0

如果你想打電話'bash' ,那麼你需要'/ bin/bash << \ EOF',那麼它不是一個shebang。 '\'因爲你不想在'tcsh'腳本中執行子shell。加上'echo'後面的子shell是無用的 – Bernhard

+1

另外,你在那裏有一些狂野的[無用的反引號](http://partmaps.org/era/unix/award.html#backticks)。 – tripleee

+2

'<<'EOF''可以防止在父shell中發生擴展。 –

回答

3

通常當你嘗試grep一個進程的名字,你會得到一個額外的匹配線grep本身,例如:

$ ps xa | grep something 
57386 s002 S+  0:00.01 grep something 

所以,即使沒有匹配的過程中,你會得到一個匹配線。

ps -e | grep stupid_test | grep -v grep | wc -l 

由於tripleee建議,甚至更好的修復程序編寫grep這樣的:

ps -e | grep [s]tupid_test 

模式的含義是完全一樣的,你可以通過在管道加入grep -v grep修復,但這樣它不會再匹配grep本身,因爲字符串"grep [s]tupid_test"與正則表達式/[s]tupid_test/不匹配。

順便說一句我會重寫你的腳本是這樣,清潔:

/bin/bash <<EOF 
while :; do 
    s=$(ps -e | grep [s]tupid_test) 
    test "$s" || break 
    echo test program is still running 
    echo "$s" 
    sleep 10 
done 
EOF 

還是一個比較懶惰,但也許足以變異(由bryn暗示):

/bin/bash <<EOF 
while ps -e | grep [s]tupid_test 
do 
    echo test program is still running 
    sleep 10 
done 
EOF 
+0

對於這種情況,pgrep是一個非常有用的工具。 –

+0

我觀察到ps的行爲,如果我使用'ps -x',但不是'ps -e' – aestrivex

+0

@aestrivex在哪個操作系統中是你? – janos