#! / 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
работает, как ожидалось
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 ответов
"kill-ability" в командной строке смогите адресованным портативно и надежно используя PID backgrounded процесса полученного от 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
Я не думаю, что вы можете положиться на 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
хотя я все равно хотел бы решение, которое делает языки сценариев как кросс-платформенными, так и простыми для мониторинга из командной строки, Если вы просто ищете альтернативу killall <scriptname>
чтобы остановить пользовательские службы, вот как я решил это:
kill `ps -fC <interpreterName> | sed -n '/<scriptName>/s/^[^0-9]*\([0-9]*\).*$//gp'`
для тех, кто не слишком хорошо знаком с ps и regexes,ps
' s -f
модификатор имеет список "полный" набор информации о процессе, включая его аргументы командной строки, и -C
говорит ему фильтровать список только команды, соответствующие следующему аргументу командной строки. Заменить <interpreterName>
С python
или node
или что-то еще.
sed
' s -n
аргумент говорит ему ничего не печатать по умолчанию, и скрипт regex должен явно указать, что вы хотите что-то напечатать.
в регулярном выражении, первый /<scriptName>/
указывает фильтровать результаты только по строкам, содержащим внутреннее регулярное выражение. Вы можете заменить <scriptName>
С envtest
, например.
в s
указывает, что будет следовать регулярное выражение подстановки. /^[^0-9]*\([0-9]*\).*$/
быть частью соответствия линии и //
быть частью замены. В соответствующей части строки ^
в начале и $
в самом конце означает, что матч должен начинаться с начала строки и заканчиваться в конце строки-вся проверяемая строка должна быть заменена.
на [^0-9]*
включает в себя несколько вещей: []
используются для определения набора допустимых письмена. В этой части регулярного выражения тире -
- означает диапазон символов, так что он расширяется до 0123456789
. The ^
здесь означает "не" и сразу означает "соответствовать любому символу, который не является числом". Звездочка *
после этого означает, что он будет продолжать совпадать с символами в этом наборе, пока не встретит несоответствующий символ, в данном случае число.
на \([0-9]*\)
имеет две части,\(\)
и [0-9]*
. Последнее должно быть легко следовать из предыдущее объяснение: он соответствует только числам и захватывает столько, сколько может. The \(\)
означает сохранение содержимого того, что соответствует временной переменной. (В других версиях регулярных выражений, включая Javascript и Perl,()
используется, вместо этого.)
наконец,.*
значит Матч всех остальных символов, как .
означает любой возможный характер.
на //
часть говорит, чтобы заменить согласованную часть линии (которая является всей линией в этом случай) с , который является ссылкой на сохраненную временную переменную (если бы было два
\(\)
разделы, первый в регулярном выражении будет и второй
).
на g
после этого означает быть "жадным" и запускать этот соответствующий код на каждой встреченной строке, а p
означает печать любой строки, которая достигла этой точки.
технически, это взорвется, если у вас есть несколько копий вашего сценария, и вы действительно хочется немного потяжелее:
ps -fC <interpreterName> | sed -n '/<scriptName>/s/^[^0-9]*\([0-9]*\).$/kill /gp' | bash
если вы хотите действительно реплицировать функциональность kill*all*, но это порождает отдельную оболочку bash для каждого сценария, который вы хотите убить.
в комментарии вы говорите, что проблема в том, что разные системы (особенно 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
, но стоит попробовать.