Получить pid текущей подоболочки

Я пытаюсь получить pid текущей исполняемой подсели, но $$ возвращает родительский pid:

#!/usr/bin/sh

x() {
  echo "I am a subshell x echo 1 and my pid is $$"
}

y() {
  echo "I am a subshell y echo 1 and my pid is $$"
}


echo "I am the parent shell and my pid is $$"
x &
echo "Just launched x and the pid is $! "

y &
echo "Just launched y and the pid is $! "

wait

Выход

I am the parent shell and my pid is 3107
Just launched x and the pid is 3108
I am a subshell x echo 1 and my pid is 3107
Just launched y and the pid is 3109
I am a subshell y echo 1 and my pid is 3107

Как вы можете видеть выше, когда я запускаю $$ из функции, которую я создал, она не отображает PID, как при я $! из родительской оболочки.

Ответы

Ответ 1

Современный bash

Если вы используете bash v4 или выше, PID подоболочки доступен в $BASHPID. Например:

$ echo $$ $BASHPID ; ( echo $$ $BASHPID  )
32326 32326
32326 1519

В основной оболочке $BASHPID совпадает с $$. В подоболочке он обновляется до PID подповерхности.

Старый bash (версия 3.x или ранее)

Перед версией 4 вам понадобится обходной путь:

$ echo $$; ( : ; bash -c 'echo $PPID' )
11364
30279

(Совет шляпы: kubanczyk)

Почему двоеточие?

Обратите внимание, что без двоеточия рабочий процесс работает не:

$ echo $$; ( bash -c 'echo $PPID' )
11364
11364

Похоже, что в приведенном выше примере подоболочка никогда не создается, и, следовательно, второй оператор возвращает PID основной оболочки. В отличие от этого, если мы помещаем два выражения внутри парнеров, создается подоболочка, и выход будет таким, какой мы ожидаем. Это верно, даже если другое выражение представляет собой просто двоеточие, :. В оболочке : не работает: ничего не делает. Однако в нашем случае мы вынуждаем создание подоболочки, которой достаточно, чтобы выполнить то, что мы хотим.

тир

В debian-подобных системах dash является оболочкой по умолчанию (/bin/sh). Подход PPID работает для dash, но с еще одним завихрением:

$ echo $$; (  dash -c 'echo $PPID' ) 
5791
5791
$ echo $$; ( : ; dash -c 'echo $PPID' )
5791
5791
$ echo $$; (  dash -c 'echo $PPID'; : )   
5791
20961

С dash, поместив команду : до того, как команда не будет достаточной, но поместив ее после нее.

POSIX

PPID включен в спецификацию POSIX.

Портативность

mklement0 сообщает, что следующее работает как с bash, dash, и zsh , но не ksh:

echo $$; (sh -c 'echo $PPID' && :)

Ответ 2

Выход правильный.

Здесь из справочной страницы bash.

Специальные параметры

В оболочке рассматриваются несколько параметров. К этим параметрам можно отнести только ссылки; присвоение им не разрешено.

* Расширяется до позиционных параметров, начиная с одного. Когда расширение происходит в двойных кавычках, оно расширяется до одного слова со значением каждого                   параметр, разделенный первым символом специальной переменной IFS. То есть "$*" эквивалентно "$1c$2c...", где c - первый символ                   значение переменной IFS. Если IFS не задано, параметры разделяются пробелами. Если IFS равно null, параметры объединяются без промежуточных разделителей.
@ Расширяется до позиционных параметров, начиная с одного. Когда расширение происходит в двойных кавычках, каждый параметр расширяется до отдельного слова. Что                   is, "[email protected]" эквивалентно "$1" "$2" ... Если двойное кавычное разложение происходит внутри слова, разложение первого параметра соединяется с начальной частью исходного слова, а разложение последнего параметра соединяется с последняя часть исходного слова. Когда нет позиционного                   параметры, "[email protected]" и [email protected] расширяются до нуля (т.е. удаляются).
# Расширяется до числа позиционных параметров в десятичном формате.
? Расширяется до статуса выхода последнего выполненного переднего плана.
- Расширяется до текущих флажков опций, как указано при вызове, с помощью встроенной команды set или тех, которые установлены самой оболочкой (например, опция -i).
$ Расширяется до идентификатора процесса оболочки. В подтесте () она расширяется до идентификатора процесса текущей оболочки, а не подоболочки.
! Расширяется до идентификатора процесса последней выполненной фоновой (асинхронной) команды.

Чтобы получить PID внутри подоболочки, вы можете использовать BASHPID. Это переменная bash только env.

Ваш новый script будет выглядеть следующим образом.

#!/bin/bash

x() {
  echo "I am a subshell x echo 1 and my pid is $BASHPID"
}

y() {
  eval echo "I am a subshell y echo 1 and my pid is $BASHPID"
}


echo "I am the parent shell and my pid is $$"
x &
echo "Just launched x and the pid is $! "

y &
echo "Just launched y and the pid is $! "

wait

Ответ 3

@John1024 ответ отличный, но там есть небольшая проблема.

когда команда запускается как (...), команда запускается в новом подпроцессе, поэтому

( : ; bash -c 'echo $PPID' ) 

вернет process_id из (...) , не идентификатор процесса функции, который вызывает (...)

если вам нужна функция process_id, вы можете просто запустить:

$SHELL -c 'echo $PPID'

и process_id будет передан в stderr

если вы хотите получить функцию process_id из переменной, вы можете запустить:

$SHELL -c 'echo $PPID' | read -s func_pid

тогда вы можете получить pid из переменной $ {func_pid}

примечание: не запускайте эту команду в (...), иначе она вернет process_id of (...)

Ответ 4

Окружающая среда:

SUSE Linux Enterprise Server 10 SP2 (i586)

GNU bash, версия 3.1.17 (1) -release (i586-suse-linux) Copyright (C) 2005 Free Software Foundation, Inc.

#!/usr/bin/sh

x() {
  mypid=$(awk 'BEGIN {print PROCINFO["ppid"] ; exit}')
  echo "I am a subshell x echo 1 and my pid is $mypid"
}

y() {
  mypid=$(awk 'BEGIN {print PROCINFO["ppid"] ; exit}')
  echo "I am a subshell y echo 1 and my pid is $mypid"
}


echo "I am the parent shell and my pid is $$"
x &
echo "Just launched x and the pid is $! "

y &
echo "Just launched y and the pid is $! "

wait

Результат:

I am the parent shell and my pid is 27645
Just launched x and the pid is 27646
Just launched y and the pid is 27647
I am a subshell y echo 1 and my pid is 27647
I am a subshell x echo 1 and my pid is 27646

Ответ 5

Если вы используете Linux-kernel, вы можете использовать функцию Linux-kernel /proc/self для этого:

В простейшем виде: cd -P/proc/self && basename "${PWD}"

Чтобы сохранить переменные PWD и OLDPWD: PWD_BACKUP="${PWD}";OLDPWD_BACKUP="${OLDPWD}";cd -P/proc/self && basename "${PWD}";cd "${PWD_BACKUP}";OLDPWD="${OLDPWD_BACKUP}"

Например:

$ cd -P /proc/self && basename "${PWD}"
26758
$ (cd -P /proc/self && basename "${PWD}")
26959
$ (cd -P /proc/self && basename "${PWD}")
26961
$ 

Ответ 6

Лучше использовать $(exec sh -c 'echo $PPID') а не уловки, показанные в ответе John1024 (эти уловки не работают в современных оболочках в настоящее время, когда я пишу свой ответ).

Посмотрите этот вопрос: https://unix.stackexchange.com/info/484442/how-can-i-get-the-pid-of-a-subshell