#!/ usr / bin / env и имена процессов: переносимость по цене? - PullRequest
7 голосов
/ 27 июня 2011

Есть много хороших причин для использования #! / USR / бен / окр. Итог: он делает ваш код более переносимым. Ну, Сорта. Проверьте это ....


У меня есть два почти идентичных сценария, bintest.py

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

и envtest.py

#! /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

но envtest.py делает что-то неоптимальное

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

Мы увидели, что использование #! /usr/bin/env заставило процесс получить имя "python", а не "envtest.py", что делает наш killall неэффективным. На каком-то уровне кажется, что мы обменяли один вид переносимости на другой: теперь мы можем легко менять интерпретаторы Python, но мы потеряли «возможность уничтожения» в командной строке. Что с этим? Если здесь есть лучшая практика для достижения обоих, что это?

Ответы [ 4 ]

3 голосов
/ 22 апреля 2012

«kill-Способность» в командной строке можно адресовать переносимо и надежно, используя PID фонового процесса, полученного из переменной $! shell.

$ ./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 с вашей заявкой.

В этом посте Stackoverflow обсуждается установка заголовка процесса в python

0 голосов
/ 18 апреля 2012

Хотя мне все еще хотелось бы решение, которое делает языки сценариев кроссплатформенными и простыми для мониторинга из командной строки, если вы просто ищете альтернативу killall <scriptname> для остановки пользовательских служб, вот как я решил это:

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

Для тех, кто не слишком знаком с ps и регулярными выражениями, модификатор ps -f имеет список «полного» набора информации о процессе, включая аргументы командной строки, а -C сообщает ему фильтровать список только по командам, которые соответствуют следующему аргументу командной строки. Замените <interpreterName> на python или node или что-либо еще.

Аргумент

sed -n говорит, что по умолчанию он ничего не печатает, а сценарий регулярного выражения должен явно указывать, что вы хотите что-то напечатать.

В регулярном выражении первый /<scriptName>/ говорит ему отфильтровать результаты только по строкам, содержащим внутреннее регулярное выражение. Вы можете заменить <scriptName> на envtest, например.

s указывает на то, что последует регулярное выражение подстановки. /^[^0-9]*\([0-9]*\).*$/ является частью совпадения строк и /\1/ является частью замещения. В части совпадения строк ^ в самом начале и $ в самом конце означают, что совпадение должно начинаться с начала строки и заканчиваться в конце строки - всей проверяемой строки подлежит замене.

[^0-9]* включает в себя несколько вещей: [] используются для определения набора допустимых символов. В этой части регулярного выражения тире - означает диапазон символов, поэтому он расширяется до 0123456789. ^ здесь означает «не» и сразу означает «соответствует любому символу, который НЕ является числом». Звездочка * впоследствии означает сохранение соответствующих символов в этом наборе, пока не встретится несовпадающий символ, в данном случае число.

У \([0-9]*\) есть две части, \(\) и [0-9]*. Последнее должно легко следовать из предыдущего объяснения: оно соответствует только числам и захватывает столько, сколько может. \(\) означает сохранение содержимого того, что соответствует временной переменной. (В других версиях RegEx, включая Javascript и Perl, вместо этого используется ().)

Наконец, .* означает соответствие каждому оставшемуся символу, так как . означает любой возможный символ.

Часть /\1/ говорит о замене совпавшей части строки (в данном случае это целая строка) на \1, которая является ссылкой на сохраненную временную переменную (если их было два \(\)) разделы, первый в RegEx будет \1, а второй \2).

g впоследствии означает «жадность» и запускать этот соответствующий код на каждой встреченной строке, а p означает печать любой строки, которая достигла этой точки.

Технически, это взорвется, если у вас будет запущено несколько копий скрипта, и вы действительно захотите немного тяжелее:

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

Если вы хотите по-настоящему копировать функциональность kill * all *, но при этом создается отдельная оболочка bash для каждого сценария, который вы хотите уничтожить.

0 голосов
/ 18 апреля 2012

В комментарии вы говорите, что проблема в том, что разные системы (особенно 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 голосов
/ 30 июня 2011

Я не думаю, что вы можете положиться на 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
...