web-dev-qa-db-fra.com

Récupère le pid du sous-shell actuel

J'essaie d'obtenir le pid d'un sous-shell en cours d'exécution - mais $$ ne renvoie que le pid parent:

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

Sortie

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

Comme vous pouvez le voir ci-dessus, lorsque j'exécute $$ à partir de la fonction que j'ai expliquée en arrière-plan, il n'affiche pas le PID comme lorsque j'ai $! à partir du Shell parent.

21
awojo

Bash moderne

Si vous utilisez bash v4 ou une version ultérieure, le PID du sous-shell est disponible dans $BASHPID. Par exemple:

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

Dans le shell principal, $BASHPID est identique à $$. Dans le sous-shell, il est mis à jour vers le PID du sous-shell.

Old bash (version 3.x ou antérieure)

Avant la version 4, vous avez besoin d’un solution de contournement :

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

(Pointe du chapeau: kubanczyk)

Pourquoi le colon?

Notez que, sans les deux points, la solution de contournement fait not work:

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

Il semble que, dans ce qui précède, un sous-shell n'est jamais créé et, par conséquent, la deuxième instruction renvoie le PID du shell principal. En revanche, si nous plaçons deux instructions à l’intérieur des parenthèses, le sous-shell est créé et la sortie est conforme aux attentes. Cela est vrai même si l'autre instruction est un simple deux-points, :. Dans Shell, le : est une non-opération: il ne fait rien. Cependant, dans notre cas, cela oblige à créer le sous-shell, ce qui est suffisant pour accomplir ce que nous voulons.

Tiret

Sur les systèmes de type debian, dash est le shell par défaut (/bin/sh). L'approche PPID fonctionne pour dash mais avec une autre tournure:

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

Avec dash, placer la commande : avant la commande n'est pas suffisant, mais le placer après l'est.

POSIX

PPID est inclus dans la spécification POSIX .

Portabilité

mklement0 indique que les opérations suivantes fonctionnent telles quelles avec bash, dash, et zsh mais pas ksh:

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

La sortie est correcte.

Voici la page de manuel de bash.

Paramètres spéciaux

Le shell traite spécialement plusieurs paramètres. Ces paramètres ne peuvent être référencés que; leur assignation n'est pas autorisée.

* Se développe jusqu'aux paramètres de position, en commençant par un. Lorsque le développement se produit entre guillemets doubles, il se développe en un seul mot avec la valeur de chaque paramètre Séparé par le premier caractère de la variable spéciale IFS. Autrement dit, "$*" est équivalent à "$1c$2c...", où c est le premier caractère de la valeur De la variable IFS. Si IFS n'est pas défini, les paramètres sont séparés par des espaces. Si IFS est null, les paramètres sont joints sans séparateurs intermédiaires.
@ Se développe jusqu'aux paramètres de position, en commençant par un. Lorsque le développement se produit entre guillemets doubles, chaque paramètre se développe dans un mot distinct. Si Est, "$@" est équivalent à "$1" "$2" ... Si le développement entre guillemets doubles se produit dans un mot, le développement du premier paramètre est joint au début du mot original et au développement du dernier paramètre avec la dernière partie du mot original. Lorsqu'il n'y a pas de paramètre de position , "$@" et $@ sont étendus à rien (c'est-à-dire qu'ils sont supprimés).
# Se développe en nombre de paramètres de position en décimal.
? Développe le statut de sortie du pipeline de premier plan exécuté le plus récemment.
- Développe les indicateurs d'option actuels spécifiés lors de l'appel, à l'aide de la commande intégrée set ou de ceux définis par le shell lui-même (comme l'option -i).
$ Développe l'ID de processus du shell. Dans un sous-shell (), il se développe en ID de processus du shell en cours, pas du sous-shell.
! Développe l'ID de processus de la commande d'arrière-plan (asynchrone) exécutée le plus récemment.

Pour obtenir le PID à l'intérieur d'un sous-shell, vous pouvez utiliser BASHPID. Ceci est une variable env uniquement bash.

Votre nouveau script ressemblera à ceci.

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

La réponse de @ John1024 est excellente, mais il y a un petit problème.

lorsqu'une commande est exécutée comme (...), la commande sera exécutée dans un nouveau sous-processus, donc 

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

retournera l'ID de processus de (...) , et non l'ID de processus de la fonction qui appelle (...)

si vous voulez le process_id de la fonction, vous pouvez simplement exécuter: 

$Shell -c 'echo $PPID'

et le process_id sera envoyé à stderr

si vous voulez que la fonction process_id de la fonction soit une variable, vous pouvez exécuter: 

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

alors vous pouvez obtenir le pid de la variable $ {func_pid}

note: ne lancez pas cette commande dans (...), sinon il retournera le process_id de (...)

1
Panda

Si vous utilisez le noyau Linux, vous pouvez utiliser la fonctionnalité /proc/self du noyau Linux pour faire ceci:

Dans la forme la plus simple: cd -P /proc/self && basename "${PWD}"

Pour conserver les variables PWD et OLDPWD: PWD_BACKUP="${PWD}";OLDPWD_BACKUP="${OLDPWD}";cd -P /proc/self && basename "${PWD}";cd "${PWD_BACKUP}";OLDPWD="${OLDPWD_BACKUP}"

Par exemple:

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

Environnement:

SUSE Linux Enterprise Server 10 SP2 (i586)

GNU bash, version 3.1.17 (1) - release (i586-suse-linux) Droits d'auteur (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

Résultat:

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
0
jramos