Dlaczego $$ zwraca ten sam identyfikator, co proces nadrzędny?

159

Mam problem z Bashem i nie wiem dlaczego.
Pod skorupą wpisuję:

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

"getpid" to program w C do pobierania aktualnego pid, na przykład:

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

Co mnie wprawia w zakłopotanie, to to, że:

  1. Myślę, że „(polecenie)” jest podprocesem (czy mam rację?) I myślę, że jego pid powinien być inny niż jego nadrzędny pid, ale są takie same, dlaczego ...
  2. kiedy używam mojego programu do wyświetlania pid w nawiasach, pid, który pokazuje, jest inny, czy to prawda?
  3. czy „$$” przypomina makro?

Możesz mi pomóc?

ruanhao
źródło
8
Zauważ, getpidże pokaże inny identyfikator procesu, nawet jeśli nie został uruchomiony w podpowłoce.
chepner
1
@Marian echo $$ $BASHPID ; ( echo $$ $BASHPID )udowadnia, że ​​tak. Okrągłe nawiasy tworzą podpowłokę. Instrukcje mogą zmieniać wartości zmiennych, a powłoka nadrzędna nie może widzieć tych zmian. Jest to realizowane jako fork()operacja.
Ben

Odpowiedzi:

222

$$jest zdefiniowany tak, aby zwracał identyfikator procesu rodzica w podpowłoce; ze strony podręcznika „Special Parameters”:

$ Interpretowany jako identyfikator procesu powłoki. W () podpowłoce rozwija się do identyfikatora procesu bieżącej powłoki, a nie podpowłoki.

W bash4 możesz uzyskać identyfikator procesu dziecka za pomocą BASHPID.

~ $ echo $$
17601
~ $ ( echo $$; echo $BASHPID )
17601
17634
Chepner
źródło
16
„rodzic” jest nieco mylący (przynajmniej tak było dla mnie), w rzeczywistości jest to powłoka „najwyższego poziomu”. Na przykład: echo $$; (echo $$; (echo $$))powtarza ten sam pid trzy razy
Martin Bouladour,
1
Dobrze; Powinienem był powiedzieć, że wartość jest dziedziczona z powłoki nadrzędnej (która odziedziczyła wartość po swoim rodzicu itp.). Powłoka najwyższego poziomu ustawia ją początkowo, zamiast dziedziczyć po swoim (nie powłokowym) procesie macierzystym.
chepner
$ Expands to the process ID of the shellczy to mimo wszystko? echo $po prostu powtarza dosłowne $.
Alexander Mills
@AlexanderMills Cóż, tak; $Samo nie jest rozwinięciem parametrów. Strona podręcznika odnosi się do nazwy specjalnego parametru, którym jest $; nie twierdzi, że $samo się rozszerza.
chepner
Ok, szczerze mówiąc nie mam pojęcia, co to znaczy, ale echo $BASHPIDdziała w bash 4 i 5 (ale nie w wersji 3.2.57 na MacOS)
Alexander Mills
81

Możesz użyć jednego z poniższych.

  • $! to PID ostatniego procesu w tle.
  • kill -0 $PID sprawdza, czy nadal działa.
  • $$ to PID bieżącej powłoki.
craken
źródło
2
Czy nie powinno być drugiego punktu, kill -0 $!jeśli mówimy o procesach w tle? PIDnie jest domyślnie ustawiona na nic.
Isaac Freeman,
26
  1. Nawiasy wywołują podpowłokę w Bash . Ponieważ jest to tylko podpowłoka, może mieć ten sam PID - zależy od implementacji.
  2. Wywoływany program w C jest oddzielnym procesem, który ma swój własny unikalny PID - nie ma znaczenia, czy jest w podpowłoce, czy nie.
  3. $$jest aliasem w Bash do bieżącego PID skryptu . Zobacz różnice między $$i $BASHPIDtutaj oraz tuż nad dodatkową zmienną, $BASH_SUBSHELLktóra zawiera poziom zagnieżdżenia.
Niels Keurentjes
źródło
4

Spróbuj, getppid()jeśli chcesz, aby program C wypisał PID twojej powłoki.

Alex
źródło
2

Gdybyś pytał, jak uzyskać PID znanego polecenia, przypominałoby to coś takiego:

Jeśli wydałeś poniższe polecenie # Wydane polecenie to ***

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


Wtedy użyłbyś:

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

To, co się tutaj dzieje, to potokowanie wszystkich potrzebnych unikalnych znaków do pola i to pole może być powtórzone przy użyciu

echo $ PIDs

Don-Pierre Halfaway
źródło
1

to jedyny sposób na uzyskanie prawidłowego pid

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

to samo fajne pracowało dla sub

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

echo "pid = $$"

(SUB)

sprawdź wyjście

pid = 8099
8099 != 8100
ARTEM LAPKIN
źródło
Fajny pomysł, ale czy nie da ci to pid widelca, który powłoka uruchomiła, aby uchwycić wynik cięcia? Jeśli uruchomię to dwukrotnie, raz z echo $ (...) i raz bez, to otrzymam różne odpowiedzi.
Martin Dorey