Я хочу запустить процесс (например, myCommand) и получить его PID (чтобы позволить убить его позже).
Я пробовал PS и фильтр по имени, но я не могу отличить процесс по именам
myCommand
ps ux | awk '/<myCommand>/ {print $2}'
Потому что имена процессов не уникальны.
Я могу запустить процесс:
myCommand &
Я обнаружил, что могу получить этот PID:
echo $!
Есть ли более простое решение?
Я был бы счастлив выполнить myCommand и получить его PID в результате одной строковой команды.
myprogram
было бы здорово&
качестве предыдущей строки a , в противном случае эхо в основном возвращает пустое значение.command & echo $!
останавливает выполнение на этом шаге :(Оберните команду в небольшой скрипт
источник
Вы можете использовать
sh -c
и,exec
чтобы получить PID команды еще до ее запуска.Для начала
myCommand
, чтобы его PID печатался до его запуска, вы можете использовать:Как это устроено:
Это запустит новую оболочку, напечатает PID этой оболочки, а затем использует
exec
встроенную функцию для замены оболочки вашей командой, убедившись, что она имеет тот же PID. Когда ваша оболочка запускает команду соexec
встроенной функцией, ваша оболочка фактически становится этой командой , а не более распространенным поведением создания новой собственной копии, которая имеет свой собственный отдельный PID и которая затем становится командой.Я считаю, что это намного проще, чем альтернативы, включающие асинхронное выполнение (с
&
), управление заданиями или поиск с помощьюps
. Эти подходы хороши, но если у вас нет конкретной причины их использовать - например, возможно, команда уже запущена, и в этом случае поиск ее PID или использование управления заданиями имеет смысл - я предлагаю сначала рассмотреть этот способ. (И я бы, конечно, не подумал о написании сложного сценария или другой программы для достижения этой цели).Этот ответ включает в себя пример этой техники.
Части этой команды иногда могут быть опущены, но не всегда.
Даже если используемая вами оболочка выполнена в стиле Борна и, следовательно, поддерживает
exec
встроенную функцию с этой семантикой, вам, как правило, не следует пытаться избегать использованияsh -c
(или его эквивалента) для создания нового отдельного процесса оболочки для этой цели, поскольку:myCommand
, нет оболочки, ожидающей запуска следующих команд.sh -c 'echo $$; exec myCommand; foo
не сможет попытаться запуститьfoo
после замены себяmyCommand
. Если вы не пишете скрипт, который запускает это как последнюю команду, вы не можете просто использоватьecho $$; exec myCommand
в оболочке, где вы выполняете другие команды.(echo $$; exec myCommand)
может быть синтаксически лучше, чемsh -c 'echo $$; exec myCommand'
, но когда вы запускаете$$
внутри(
)
, он дает PID родительской оболочки, а не самой подоболочки. Но PID подоболочки будет PID новой команды. Некоторые оболочки предоставляют свои собственные непереносимые механизмы для нахождения PID подоболочки, которые вы можете использовать для этого. В частности, в Bash 4 ,(echo $BASHPID; exec myCommand)
работает.Наконец, обратите внимание, что некоторые оболочки выполняют оптимизацию, когда они запускают команду, как если бы
exec
(то есть сначала отказываются от разветвления), когда известно, что оболочке не нужно будет ничего делать позже. Некоторые оболочки пытаются сделать это в любое время, когда выполняется последняя команда, в то время как другие будут делать это только тогда, когда нет других команд до или после команды, а другие вообще не будут делать это. В результате, если вы забудете написатьexec
и просто использовать,sh -c 'echo $$; myCommand'
это иногда даст вам правильный PID в некоторых системах с некоторыми оболочками. Я рекомендую никогда не полагаться на такое поведение , а вместо этого всегда включать,exec
когда это то, что вам нужно.источник
myCommand
, мне нужно установить несколько переменных окружения в моем скрипте bash. Будут ли они перенесены в среду, в которой выполняетсяexec
команда?exec
команду. Однако этот подход не работает, когдаmyCommand
запускаются другие процессы, с которыми вам нужно работать; когда я выдаюkill -INT <pid>
местоположение,pid
полученное таким образом, сигнал не достигает подпроцессов, запущенных с помощьюmyCommand
, тогда как, если я запускаюmyCommand
в текущем сеансе и Ctrl + C, сигналы распространяются правильно.sh -c 'echo $$; exec /usr/local/bin/mbdyn -f "input.file" -o "/path/to/outputdir" > "command_output.txt" 2>&1 &'
Я не знаю ни одного более простого решения, но не использую $! достаточно хорошо? Вы всегда можете присвоить значение некоторой другой переменной, если вам это понадобится позже, как сказали другие.
В качестве примечания, вместо ps от ps вы можете использовать
pgrep
илиpidof
.источник
используйте exec из скрипта bash после регистрации pid в файле:
пример:
Предположим, у вас есть скрипт с именем "forever.sh", который вы хотите запустить с аргументами p1, p2, p3
forever.sh исходный код:
создать reaper.sh:
запустите forever.sh через reaper.sh:
forever.sh не делает ничего, кроме записи строки в системный журнал каждые 5 секунд
теперь у вас есть pid в /var/run/forever.sh.pid
и навсегда. grep системного журнала:
Вы можете увидеть это в таблице процессов:
источник
exec "$@"
вместоexec $*
. Технически, что вам нужно сохранить, это не пробелы, а вхождения символов в параметре оболочки IFS (по умолчанию пробел, табуляция и символ новой строки).В оболочке bash альтернативой
$!
может бытьjobs -p
встроенная. В некоторых случаях!
в$!
получает интерпретатор до (или вместо) переменного расширения, что приводит к неожиданным результатам.Это, например, не будет работать:
пока это будет:
источник
Вы можете использовать что-то вроде:
Или же
Две команды могут быть соединениями с помощью
;
или&&
. Во втором случае pid будет установлен только в случае успешного выполнения первой команды. Вы можете получить идентификатор процесса от$pid
.источник
$!
после&&
или;
никогда не даст вам PID процесса, запущенного для левой части разделителя команд.$!
устанавливается только для процессов, запускаемых асинхронно (например, обычно,&
но в некоторых оболочках также есть другие методы).Это немного хакерский ответ и вряд ли подойдет большинству людей. Это также огромный риск для безопасности, поэтому не делайте этого, если вы не уверены, что будете в безопасности, а входы очищены и ... ну, вы поняли идею.
Скомпилируйте небольшую C-программу в двоичный файл с именем
start
(или как хотите), затем запустите вашу программу как./start your-program-here arg0 arg1 arg2 ...
Короче говоря, это напечатает PID
stdout
, а затем загрузит вашу программу в процесс. Он должен иметь тот же PID.источник
stdout
похоже, не записано в этом примере:RESULT="$(./start_and_get_pid.out echo yo)"; echo "$RESULT"
sleep 10 & PID_IS=$!; echo $PID_IS