2016-11-17 58 views
4

我創建了一個bash腳本,用於統計自己啓動的實例。Bash腳本錯誤地計算其本身的實例

這是(在這個例子中,我展示的實例,而不是將它們與wc -l算起):

#!/bin/bash 
nb=`ps -aux | grep count_itself.sh` 
echo "$nb" 
sleep 20 

(當然,我的劇本被命名爲count_itself.sh

在執行了它,我希望它返回兩行,但它返回三個:

[email protected]:/# ./count_itself.sh 
root 16225 0.0 0.0 12400 1176 pts/0 S+ 11:46 0:00 /bin/bash ./count_itself.sh 
root 16226 0.0 0.0 12408 564 pts/0 S+ 11:46 0:00 /bin/bash ./count_itself.sh 
root 16228 0.0 0.0 11740 932 pts/0 S+ 11:46 0:00 grep count_itself.sh 

經與&標誌執行它(即在後臺,並手動執行ps -aux位,它返回兩個,這正是我想要的:

[email protected]:/# ./count_itself.sh & 
[1] 16233 
[email protected]:/# ps -aux | grep count_itself.sh 
root  16233 0.0 0.0 12408 1380 pts/0 S 11:48 0:00 /bin/bash ./count_itself.sh 
root  16240 0.0 0.0 11740 944 pts/0 S+ 11:48 0:00 grep --color=auto count_itself.sh 

我的問題是:爲什麼ps -aux執行裏面的腳本返回一行超過預期?

或換句話說,爲什麼在我的第一個示例中創建了id爲16226的進程?

EDIT(因爲大多數人似乎誤解了我的問題):

我想知道爲什麼bash執行返回/bin/bash ./count_itself.sh兩個實例,不爲什麼它返回grep count_itself.sh

編輯2:

當然,我正在尋找一種方式來避免這種行爲,並在該腳本返回/bin/bash ./count_itself.sh只有一次。

+2

'''ps -aux | grep count_itself.sh \''在子外殼中執行,即在子進程中執行。因此,執行腳本的shell會被分叉,然後子運行'ps -aux | grep count_itself.sh'命令。 – Leon

+0

我建議:nb ='ps -aux | grep [c] ount_itself.sh – Cyrus

+2

當你執行'ps -aux | grep count_itself.sh'你的grep把它看作count_itself的一個實例。你需要改進你的正則表達式 – Stargateur

回答

1

終於找到了一種方法,雖然難看,從局部問題啓發@TomFenech掛在他answer

#!/bin/bash 
nb=$(ps f | grep '[c]ount_itself.sh' | grep -v ' \\_') 
echo "$nb" 
sleep 20 

執行:

[email protected]:/# ./count_itself.sh 
17725 pts/1 S+  0:00 \_ /bin/bash ./count_itself.sh 

執行一個已經在運行BG:

[email protected]:/# ./count_itself.sh & 
[1] 17733 
[email protected]:/# ./count_itself.sh 
17733 pts/1 S  0:00 \_ /bin/bash ./count_itself.sh 
17739 pts/1 S+  0:00 \_ /bin/bash ./count_itself.sh 

解釋(從我所理解的):

  • ps f返回活動進程樹
  • grep '[c]ount_itself.sh'限制前面的命令到的count_itself.sh

返回

17808 pts/1 S+  0:00 \_ /bin/bash ./count_itself.sh 
17809 pts/1 S+  0:00  \_ /bin/bash ./count_itself.sh 
  • grep -v ' \\_'排除包含4位(一個標籤的等效物)的行然後\_只顯示實例,其對應於子過程
4

這是一個標準問題,grep輸出ps

一種解決方案是周圍添加字符

nb=$(ps -aux | grep '[c]ount_itself.sh') 

這意味着您的grep實例不匹配本身,因爲它的參數的過程的名稱包含方括號,但該模式的一些方括號它匹配不。

正如在評論中提到的,你應該在變量周圍使用雙引號以保留空格。

您在結果中似乎有兩個相同shell的實例的原因是命令替換在子shell中執行。有關僅顯示父進程的詳細信息,請參閱this question

+0

我編輯了我的問題,有沒有辦法讓'ps -aux'不能返回子shell的執行? – roberto06

+0

編輯添加鏈接。 –

2

進程替換需要父shell啓動一個子shell,即fork和執行子shell中的指定命令。這是必需的,以便父shell不受環境變量(變量,當前工作目錄,陷阱)的影響,$(...)中所包含的腳本所做的更改。

例子:

$ cat test.sh 
#!/bin/bash 

a=1 
b="$(a=2; echo abc)" 
echo "a=$a" 
echo "b=$b" 
$ ./test.sh 
a=1   # Note that the variable 'a' preserved its value 
b=abc 

它是作爲分岔您看到您的腳本的額外實例的結果。

我不認爲有可能從輸出中可靠地消除那些不需要的進程,因爲原則上腳本可以合法地啓動自己的另一個實例(它將作爲子進程運行),並且您無法區分這兩種情況之間。

一個棘手的解決方案是讓腳本在指定位置(例如/tmp/your_script_name)上創建一個PID文件,並在終止時刪除它。

2

我建議未來的方式:

排除所有的過程,父母是自己:

ps --pid $$ -N -a | grep count_itself.sh 

這意味着顯示所有命令,父母是不是我自己了(所以這排除您的grep的過程和你的叉子過程執行計數器句)

+0

它仍然回聲兩行,只有'--pid $$'標誌,如果我添加'-N'標誌,它什麼也不會響應。我正在尋找中間某個地方的結果:P – roberto06

+0

我想,如果用'-N'標誌沒有返回任何東西,那是因爲你是唯一運行的實例,可能是,如果你想自己計算一下,你可以加1到結果。 –