Command line #! /usr/bin/env和进程名称:价格上的可移植性?

Command line #! /usr/bin/env和进程名称:价格上的可移植性?,command-line,environment-variables,portability,kill,shebang,Command Line,Environment Variables,Portability,Kill,Shebang,有很多东西可供使用/usr/bin/env。一句话:它使您的代码更具可移植性。嗯,好吧。看看这个 我有两个几乎相同的脚本,bintest.py #! /usr/bin/python import time time.sleep(5*60) #! /usr/bin/env python import time time.sleep(5*60) 和envetest.py #! /usr/bin/python import time time.sleep(5*60) #! /usr/bin/e

有很多东西可供使用/usr/bin/env。一句话:它使您的代码更具可移植性。嗯,好吧。看看这个


我有两个几乎相同的脚本,
bintest.py

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

#! /usr/bin/python
import time
time.sleep(5*60)
#! /usr/bin/env python
import time
time.sleep(5*60)
请注意,它们只是在不同的方面有所不同


bintest.py
按预期运行

br@carina:~$ ./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 br@carina:~$ [1]+ Terminated ./bintest.py

我们看到的是使用
#/usr/bin/env
导致进程收到名称“python”而不是“envetest.py”,从而使我们的
killall
无效。在某种程度上,我们似乎已经用一种可移植性换了另一种:我们现在可以轻松地交换python解释器,但我们已经失去了命令行上的“杀戮能力”。怎么回事?如果这里有一个实现这两个目标的最佳实践,那么它是什么?

我认为您不能依靠
killall
使用脚本名称来一直工作。在Mac OS X上,运行两个脚本后,我从
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

虽然我仍然希望有一个解决方案能够使脚本语言跨平台且易于从命令行进行监控,但如果您只是想寻找一种替代方法来停止定制服务,下面是我如何解决的:

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

如果您想真正复制kill*all*功能,但这会为您想要杀死的每个脚本生成一个单独的bash shell。

在一条评论中,您说问题在于不同的系统(特别是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交互,但值得一试。

命令行上的“kill ability”可以通过使用从shell
$获得的后台进程的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
$ 
和envetest.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模块


这篇Stackoverflow帖子讨论了
ps
killall
的内部结构在不同的系统中是不同的,因此部分问题是使用
killall
作为批评标准。不过,这个问题很有趣。还有一些不使用
#的好理由/usr/bin/env
;请参阅和。@KeithThompson,我之所以在这上面悬赏,是因为我正在编写一组需要在Linux和Mac OS X上运行的脚本,它们将所需的可执行文件放在$PATH的不同位置,但我仍然希望
top
正确列出每一个脚本所以你可以区分一个脚本和另一个脚本。解决这个问题的方法不是使用一个安装脚本来代替shebang行上正确的本地解释器吗?不过,这就是问题所在;您不能依赖
/tmp/
在重新启动期间存在,因此您的脚本不能依赖它存在。不过,这很接近,因为
killall
工作正常。@DavidEllis:这就是为什么我说换一个位置可能会更好——但你可以有一个脚本,在启动时创建并填充
/tmp/bin
。这取决于您对系统的控制程度。