7

有很多goodreasons使用#!在/ usr/bin中/ env的。底線:它使你的代碼更加便攜。好吧,呃。檢查了這一點....#!/usr/bin/env和進程名稱:可移植性的價格?


我有兩個幾乎相同的腳本,bintest.py

#! /usr/bin/python 
import time 
time.sleep(5*60) 

envtest.py

#! /usr/bin/env python 
import time 
time.sleep(5*60) 

注意,他們只在他們shebangs不同。


bintest.py預期

 
[email protected]:~$ ./bintest.py & ps && killall bintest.py 
[1] 15061 
    PID TTY   TIME CMD 
14625 pts/0 00:00:00 bash 
15061 pts/0 00:00:00 bintest.py 
15062 pts/0 00:00:00 ps 
[email protected]:~$ 
[1]+ Terminated    ./bintest.py 

envtest.py運行做了低於最佳

 
[email protected]:~$ ./envtest.py & ps && killall envtest.py 
[1] 15066 
    PID TTY   TIME CMD 
14625 pts/0 00:00:00 bash 
15066 pts/0 00:00:00 python 
15067 pts/0 00:00:00 ps 
envtest.py: no process found 
[email protected]:~$ killall python 
[email protected]:~$ 
[1]+ Terminated    ./envtest.py 

我們所看到的是,使用#! /usr/bin/env導致進程接收名稱「python」而不是「envtest.py」,從而渲染我們的killall無效。在某種程度上,我們似乎已經爲另一種方式交換了一種可移植性:我們現在可以輕鬆地換出python解釋器,但是我們已經在命令行上失去了「可執行性」。那是怎麼回事?如果這裏有一個最佳實踐,那麼它是什麼?

+0

也有一些很好的理由*不*使用'#在/ usr/bin中/ env'!;看到[這個問題](http://unix.stackexchange.com/q/29608/10454)和[我的回答](http://unix.stackexchange.com/a/29620/10454)。 –

+0

@KeithThompson,我把賞金放在這個上的原因是因爲我正在研究一組需要在Linux和Mac OS X上運行的腳本,並且他們將需要的可執行文件放在$ PATH的不同位置,但是我仍然喜歡''top''來正確列出每一個,這樣你就可以區分一個腳本和另一個腳本。 –

+0

解決方案不是使用安裝腳本替換shebang行上正確的本地解釋器嗎? – tripleee

回答

3

命令行上的「kill-ability」可以通過使用從外殼$!變量中獲得的後退過程的PID可移植且可靠地尋址。

$ ./bintest.py & bg_pid=$! ; echo bg_pid=$bg_pid ; ps && kill $bg_pid 
[1] 2993 
bg_pid=2993 
    PID TTY   TIME CMD 
2410 pts/0 00:00:00 bash 
2993 pts/0 00:00:00 bintest.py 
2994 pts/0 00:00:00 ps 
$ 
[1]+ Terminated    ./bintest.py 
$ 

和envtest.py

$ ./envtest.py & bg_pid=$! ; echo bg_pid=$bg_pid ; ps && kill $bg_pid 
[1] 3016 
bg_pid=3016 
    PID TTY   TIME CMD 
2410 pts/0 00:00:00 bash 
3016 pts/0 00:00:00 python 
3017 pts/0 00:00:00 ps 
$ 
[1]+ Terminated    ./envtest.py 
$ 

由於@Adam Bryzak指出,無論是腳本導致進程標題在Mac OS X這樣設置,如果該功能是一個堅定的要求,你可能需要在應用程序中安裝和使用python模塊setproctitle

這個崗位#1討論setting process title in python

0

我不認爲你可以依靠killall使用腳本名稱一直工作。在Mac OS XI得到ps同時運行腳本後的輸出如下:

2108 ttys004 0:00.04 /usr/local/bin/python /Users/adam/bin/bintest.py 
2133 ttys004 0:00.03 python /Users/adam/bin/envtest.py 

和運行killall bintest.py結果

No matching processes belonging to you were found 
+0

'ps'和'killall'的內部結構在系統之間是不同的,所以問題的一部分是使用'killall'作爲批評的標準。有趣的問題,雖然。 – tripleee

0

雖然我還是喜歡一個解決方案,使腳本語言都跨平臺和從命令行易於監視,如果您只是尋找替代killall <scriptname>來停止自定義服務,以下是我如何解決它:

kill `ps -fC <interpreterName> | sed -n '/<scriptName>/s/^[^0-9]*\([0-9]*\).*$/\1/gp'` 

對於那些不太熟悉ps和正則表達式的人,ps-f修飾符已經列出了關於進程的一整套「完整」信息,包括其命令行參數,並且-C指示它將列表過濾爲僅命令與下一個命令行參數相匹配。將<interpreterName>替換爲pythonnode或其他。

sed-n參數告訴它默認情況下不打印任何東西,並且正則表達式腳本必須明確指出要打印的東西。

在正則表達式中,第一個/<scriptName>/指示它將結果過濾爲僅包含內部正則表達式的行。例如,您可以用envtest代替<scriptName>

s表示將出現替換正則表達式。 /^[^0-9]*\([0-9]*\).*$/是行匹配部分,並且/\1/是替代部分。在線匹配部分,最開始的^和最末尾的$意味着匹配必須從線的開始處開始並結束於線的末尾 - 要檢查的整個線將被替換。

[^0-9]*涉及一些事情:[]用於定義一組允許的字符。在這部分的正則表達式中,破折號-表示一個字符範圍,因此它擴展爲。這裏的^表示「不」,並且立即表示「匹配不是數字的任何字符」。之後的星號*表示繼續匹配該組中的字符,直到遇到不匹配的字符,在這種情況下是數字。

\([0-9]*\)有兩個部分,\(\)[0-9]*。後者應該易於遵循前面的解釋:它只匹配數字,並且儘可能多地抓取。 \(\)的意思是保存與臨時變量匹配的內容。 (在其它正則表達式版本,包括Javascript和Perl中,()被使用,來代替。)

最後,.*意味着每其餘的字符匹配,如.指任何可能的字符。

/\1/部說來代替線的匹配部分(它是在這種情況下,整行)與\1,這是所保存的臨時變量的引用(如果出現了2個\(\)部分,第一個在RegEx中將是\1和第二個\2)。

g之後的意思是「貪婪」並在遇到的每一行上運行這個匹配的代碼,並且p意味着打印已經達到該點的任何行。

從技術上講,這將炸燬,如果你有你的腳本運行的多個副本,和你真正想要的稍重:

ps -fC <interpreterName> | sed -n '/<scriptName>/s/^[^0-9]*\([0-9]*\).$/kill \1/gp' | bash 

如果你想真正複製殺*所有*的功能,但這會爲每個想要殺死的腳本生成一個單獨的bash shell。

0

在評論中,你說問題是不同的系統(特別是MacOS和Linux)將可執行文件放在不同的目錄中。

您可以通過在兩個系統上創建具有相同完整路徑的目錄並創建與可執行文件的符號鏈接來解決此問題。

Ubuntu,Solaris和Cygwin上的實驗表明,在shebang中命名的可執行文件可以是符號鏈接。 (我沒有訪問了MacOS系統,所以我不知道它會在那裏工作。)

例如,我的Ubuntu系統上:

$ cat hello.bash 
#!/tmp/bin/bash 

echo Yes, it works 
$ ./hello.bash 
-bash: ./hello.bash: /tmp/bin/bash: bad interpreter: Permission denied 
$ mkdir /tmp/bin 
$ ln -s /bin/bash /tmp/bin/. 
$ ./hello.bash 
Yes, it works 
$ 

上設置的公共目錄所有相關的系統都是不方便的。 (在本例中,我使用/tmp;不同的位置可能會更好。)

我不知道這將如何與killall交互,但它是值得嘗試。

+0

儘管如此,你不能依靠'/ tmp /''在重新啓動時存在,所以你的腳本不能依賴它。不過,這很接近,因爲「killall」按預期工作。 –

+0

@DavidEllis:這就是爲什麼我說不同的位置可能會更好 - 但是你可以有一個腳本在啓動時創建和填充'/ tmp/bin'。這取決於你對系統有多少控制。 –