Почему $$ возвращает тот же идентификатор, что и родительский процесс?

У меня проблема с Bash, и я не знаю почему.
В оболочке я ввожу:

echo $$    ## print 2433
(echo $$)  ## also print 2433
(./getpid) ## print 2602

"getpid" - это программа на языке C для получения текущего pid, например:

   int main() {
    printf("%d", (int)getpid());
    return 0;
   }

Меня смущает то, что:

  1. Я думаю, что «(команда)» - это подпроцесс (я прав?), И я думаю, что его pid должен отличаться от родительского pid, но они такие же, почему ...
  2. когда я использую свою программу, чтобы показать pid между скобками, pid, который она показывает, отличается, это правильно?
  3. "$$" что-то вроде макроса?

Можешь мне помочь?


person ruanhao    schedule 11.01.2014    source источник
comment
Обратите внимание, что getpid будет отображать другой идентификатор процесса, даже если он не был запущен в подоболочке.   -  person chepner    schedule 11.01.2014
comment
@Marian echo $$ $BASHPID ; ( echo $$ $BASHPID ) демонстрирует, что это так. Круглые скобки образуют подоболочку. Операторы могут изменять значения переменных, и родительская оболочка не должна видеть эти изменения. Это реализовано как fork() операция.   -  person Ben    schedule 18.01.2020


Ответы (7)


$$ определен для возврата идентификатора процесса родителя в подоболочке; на странице руководства в разделе «Специальные параметры»:

$ Заменяется на идентификатор процесса оболочки. В подоболочке () он расширяется до идентификатора процесса текущей оболочки, а не до подоболочки.

В bash 4 вы можете получить идентификатор дочернего процесса с помощью BASHPID.

~ $ echo $$
17601
~ $ ( echo $$; echo $BASHPID )
17601
17634
person chepner    schedule 11.01.2014
comment
parent немного вводит в заблуждение (по крайней мере, для меня), на самом деле это оболочка верхнего уровня. Например: echo $$; (echo $$; (echo $$)) отображает один и тот же pid три раза. - person Martin Bouladour; 20.07.2017
comment
Правильно; Я должен был сказать, что значение наследуется от родительской оболочки (которая унаследовала свое значение от своего родителя и т. Д.). Оболочка верхнего уровня устанавливает его изначально, а не наследует от родительского процесса (не являющегося оболочкой). - person chepner; 20.07.2017
comment
$ Expands to the process ID of the shell все же? echo $ просто повторяет буквальный символ $. - person Alexander Mills; 31.05.2019
comment
@AlexanderMills Ну да; $ сам по себе не является расширением параметра. Страница руководства ссылается на имя специального параметра, которым является $; это не утверждает, что только $ расширяется. - person chepner; 31.05.2019
comment
Хорошо, честно говоря, я понятия не имею, что это значит, но echo $BASHPID работает в bash 4 и 5 (но не в версии 3.2.57 на MacOS) - person Alexander Mills; 31.05.2019
comment
Все расширения параметров начинаются с $, но $ также является именем одного из специальных параметров. $, #, @, * и т. Д. - некоторые из специальных параметров; $$, $#, $@, $* и т. Д. - это выражения, которые расширяются до значения каждого из них. - person chepner; 31.05.2019

Вы можете использовать одно из следующих.

  • $! - это PID последнего фонового процесса.
  • kill -0 $PID проверяет, работает ли он еще.
  • $$ - это PID текущей оболочки.
person craken    schedule 18.08.2014
comment
Разве второй пункт не должен быть kill -0 $!, если мы говорим о фоновых процессах? PID по умолчанию ничего не установлено. - person Isaac Freeman; 13.09.2019

  1. Круглые скобки вызывают подоболочку в Bash. Поскольку это всего лишь подоболочка, у нее может быть один и тот же PID - в зависимости от реализации.
  2. Программа на C, которую вы вызываете, представляет собой отдельный процесс, который имеет свой собственный уникальный PID - неважно, в подоболочке она или нет.
  3. $$ - это псевдоним в Bash для текущего PID скрипта. См. различия между $$ и $BASHPID здесь и прямо над дополнительной переменной $BASH_SUBSHELL, который содержит уровень вложенности.
person Niels Keurentjes    schedule 11.01.2014

Попробуйте getppid(), если вы хотите, чтобы ваша программа на C печатала PID вашей оболочки.

person Alex    schedule 11.01.2014
comment
Или, если вы используете Rust, просто попробуйте nix::unistd::getppid(), который получит pid родительского процесса текущего процесса - docs.rs/nix/0.18.0/nix/unistd/fn.getppid.html - person joseluisq; 12.10.2020

это единственный универсальный способ получить правильный pid

pid=$(cut -d' ' -f4 < /proc/self/stat)

такая же хорошая работа для саб

SUB(){
    pid=$(cut -d' ' -f4 < /proc/self/stat)
    echo "$$ != $pid"
}

echo "pid = $$"

(SUB)

проверить вывод

pid = 8099
8099 != 8100
person ARTEM LAPKIN    schedule 23.08.2019
comment
Хорошая идея, но разве это не даст вам pid вилки, которую оболочка запустила для захвата вывода cut? Если я запустил его дважды, один раз с echo $ (...) и один раз без него, я получу разные ответы. - person Martin Dorey; 27.08.2019

Если бы вы спрашивали, как получить PID известной команды, это выглядело бы примерно так:

Если вы ввели команду ниже # Выпущенная команда была ***

dd if = / dev / diskx of = / dev / disky


Тогда вы должны использовать:

PIDs=$(ps | grep dd | grep if | cut -b 1-5)

Что здесь происходит, так это то, что он передает все необходимые уникальные символы в поле, и это поле может быть отображено с помощью

echo $ PIDs

person Don-Pierre Halfaway    schedule 18.07.2018

если вам нужен простой сценарий оболочки для получения максимального PID с переменной, сделайте это

pid=$(cat /proc/sys/kernel/pid_max)
echo $pid

который напечатает вам максимальный PID, который может быть.

person SertseV    schedule 03.04.2021