Vraag Hoe pid van enkel begonnen proces te krijgen


Ik wil het proces starten (bijv. MyCommand) en zijn pid krijgen (om het later te kunnen doden).

Ik heb ps geprobeerd en filter op naam, maar ik kan procesnamen niet van elkaar onderscheiden

myCommand
ps ux | awk '/<myCommand>/ {print $2}' 

Omdat procesnamen niet uniek zijn.

Ik kan het proces uitvoeren door:

myCommand &

Ik heb ontdekt dat ik deze PID kan krijgen door:

echo $!

Is er een eenvoudigere oplossing?

Ik zou graag myCommand uitvoeren en de PID krijgen als resultaat van één regelopdracht.


51
2017-11-24 08:28


oorsprong




antwoorden:


Wat kan eenvoudiger zijn dan echo $!? Als één regel:

myCommand & echo $!

61
2017-11-24 08:46



Bedankt dat het samenvoegen van deze opdrachten met "&" me veel heeft geholpen. - rafalmag
in een bash-script, in een lus die programma's start, $! is niet correct. Soms retourneert het pid van het script zelf, soms van grep of awk wordt vanuit het script elke oplossing uitgevoerd om specifiek de pid van het proces te krijgen dat zojuist in dit scenario is gestart? zoiets als pid =myprogram zou geweldig zijn geweest
NB dat dit vereist dat u de opdracht start met behulp van a &als de vorige regel, anders keert de echo in principe blanco terug. - rogerdpack
toewijzen aan variabele like command & echo $! bevriest de uitvoering bij deze stap :( - Shashank Vivek
het redt mijn leven! bedankt. - temple


Wikkel de opdracht in een klein script

#!/bin/bash
yourcommand &
echo $! >/path/to/pid.file

21
2017-11-24 08:48





Ik ken geen eenvoudiger oplossing, maar gebruik geen $! goed genoeg? Je kunt de waarde altijd toewijzen aan een andere variabele als je die later nodig hebt, zoals anderen zeggen.

Als een kanttekening, in plaats van piping van ps die je zou kunnen gebruiken pgrep of pidof.


7
2017-11-24 14:13





gebruik exec van een bash-script na registratie van de pid in een bestand:

voorbeeld:

stel dat je een script hebt met de naam "forever.sh" dat je wilt uitvoeren met args p1, p2, p3

forever.sh sourcecode:

#!/bin/sh

while [ 1 -lt 2 ] ; do
    logger "$0 running with parameters \"$@\""
    sleep 5
done

maak een reaper.sh aan:

#!/bin/sh

echo $$ > /var/run/$1.pid
exec "$@"

voer forever.sh door reaper.sh:

./reaper.sh ./forever.sh p1 p2 p3 p4 &

forever.sh doet niets meer dan elke 5 seconden een regel loggen op syslog

je hebt nu de pid in /var/run/forever.sh.pid

cat /var/run/forever.sh.pid 
5780

en forever.sh gebruikt aok. syslog grep:

Nov 24 16:07:17 pinkpony cia: ./forever.sh running with parameters "p1 p2 p3 p4"

je kunt het in de procestabel zien:

ps axuwww|grep 'forever.sh p1' |grep -v grep
root      5780  0.0  0.0   4148   624 pts/7    S    16:07   0:00 /bin/sh ./forever.sh p1 p2 p3 p4

5
2018-03-20 16:58



oh, en de "oneliner": / bin / sh -c 'echo $$> / tmp / my.pid && exec programma args' & - user237419
Om interne spaties in de argumenten goed te behouden, zou u moeten gebruiken exec "$@" in plaats van exec $*. Technisch gezien is wat u moet behouden niet witruimte maar occurrences van de tekens in de IFS-shellparameter (standaard als spatie, tab en nieuwe regel). - Chris Johnsen
punt gemaakt. :) - user237419
Bedankt, ik kende de parameter $$ niet. Het kan erg handig zijn. - rafalmag


Je kunt gebruiken sh -c en exec om de PID van het commando zelfs te krijgen voor het rent.

Beginnen myCommand, zodat de PID wordt afgedrukt voordat deze begint te lopen, kunt u het volgende gebruiken:

sh -c 'echo $$; exec myCommand'

Hoe het werkt:

Dit start een nieuwe shell, drukt de PID van die shell af en gebruikt dan de exec ingebouwd vervangen de shell met uw commando, zodat deze dezelfde PID heeft. Wanneer uw shell een opdracht uitvoert met de exec builtin, je shell is werkelijk worden die opdracht, liever dan het meer gebruikelijke gedrag van het vragen van een nieuw exemplaar van zichzelf, dat zijn eigen afzonderlijke PID heeft en dat dan het commando wordt.

Ik vind dit veel eenvoudiger dan alternatieven met asynchrone uitvoering (met &), taakbeheer of zoeken met ps. Die benaderingen zijn prima, maar tenzij je een specifieke reden hebt om ze te gebruiken - bijvoorbeeld, misschien is de opdracht al aan de gang, in welk geval het zoeken naar de PID of het gebruik van taakbeheer zinvol zou zijn - ik stel voor deze als eerste te beschouwen. (En ik zou zeker niet overwegen om een ​​complex script of een ander programma te schrijven om dit te bereiken).

Dit antwoord bevat een voorbeeld van deze techniek.


Delen van die opdracht kunnen af ​​en toe worden weggelaten, maar meestal niet.

Zelfs als de shell die je gebruikt een Bourne-stijl is en dus de ondersteuning biedt exec ingebouwd met deze semantiek, moet je over het algemeen niet proberen te vermijden om te gebruiken sh -c (of equivalent) om een ​​nieuwe, scheiden shell-proces voor dit doel, omdat:

  • Zodra de schaal is geworden myCommand, er wacht geen shell om volgende opdrachten uit te voeren. sh -c 'echo $$; exec myCommand; foo zou niet kunnen proberen uit te voeren foo na zichzelf te hebben vervangen myCommand. Tenzij u een script schrijft dat dit als zijn laatste opdracht uitvoert, kunt u het niet zomaar gebruiken echo $$; exec myCommand in een shell waarin u andere opdrachten uitvoert.
  • Je kunt geen a gebruiken subshell voor deze. (echo $$; exec myCommand) kan syntactisch leuker zijn dan sh -c 'echo $$; exec myCommand', maar als je rent $$ binnen (  ), het geeft de PID van de bovenliggende shell, niet van de subshell zelf. Maar het is de PID van de subshell die de PID van het nieuwe commando zal zijn. Sommige shells bieden hun eigen niet-draagbare mechanismen voor het vinden van de PID van de subshell, die jij kon gebruik hiervoor. Met name, in Bash 4, (echo $BASHPID; exec myCommand) het werkt.

Merk tot slot op dat sommige shells een optimalisatie waar ze een commando uitvoeren als door exec (d.w.z. dat ze eerst afzien) als het bekend is dat de shell daarna niets hoeft te doen. Sommige schelpen proberen dit te doen wanneer het de laatste opdracht is die wordt uitgevoerd, terwijl anderen dit alleen doen wanneer er geen andere opdrachten voor of na de opdracht zijn, en anderen dat helemaal niet. Het effect is dat als je vergeet te schrijven exec en gebruik gewoon sh -c 'echo $$; myCommand' dan zal het soms geef je de juiste PID aan sommige systemen met sommige schelpen. Ik raad aan om nooit op te vertrouwen dergelijk gedrag, en in plaats daarvan altijd inclusief exec wanneer dat is wat je nodig hebt.


5
2017-07-19 17:02



Voordat ik kan rennen myCommand, Ik moet een aantal omgevingsvariabelen instellen in mijn bash-script. Zullen deze overbrengen naar de omgeving waarin het exec commando loopt? - user5359531
Het lijkt erop dat mijn omgeving de overstap naar de exec commando. Deze aanpak werkt echter niet wanneer myCommand start andere processen, waarmee u moet werken; wanneer ik een uitgeven kill -INT <pid> waar pid werd op deze manier verkregen, het signaal bereikt de subprocessen die zijn gestart niet myCommand, terwijl ik loop myCommand  in de huidige sessie en Ctrl + C, verspreiden de signalen correct. - user5359531
Ik heb dit geprobeerd, maar de pid van het myCommand-proces lijkt de pid-uitvoer te zijn door echo $$ +1. Doe ik iets verkeerd? - crobar
Mijn opdracht ziet er als volgt uit: sh -c 'echo $$; exec /usr/local/bin/mbdyn -f "input.file" -o "/path/to/outputdir" > "command_output.txt" 2>&1 &' - crobar


In de bash-shell een alternatief voor $! misschien wel het jobs -p ingebouwd. In sommige gevallen de ! in $! wordt geïnterpreteerd door de shell vóór (of in plaats van) de variabele uitbreiding, wat tot onverwachte resultaten leidt.

Dit werkt bijvoorbeeld niet:

((yourcommand) & echo $! >/var/run/pidfile)

terwijl dit:

((yourcommand) & jobs -p >/var/run/pidfile)

3
2017-11-24 08:46



Ik denk dat je ((jouw opdracht) & taken -p> / var / run / pid-bestand) bedoelde. - Dom
@ DominicO'Brien je hebt natuurlijk gelijk. Bedankt. - mustaccio


U kunt zoiets als gebruiken:

$ myCommand ; pid=$!

Of

$ myCommand && pid=$!

De twee opdrachten kunnen verbindingen zijn die worden gebruikt ; of &&. In het tweede geval wordt de pid alleen ingesteld als de eerste opdracht slaagt. U kunt het proces-ID ophalen $pid.


1
2017-07-26 22:52



OP wil de PID krijgen zodat hij deze later kan doden. ; en && vereisen dat het originele proces wordt afgesloten voordat de echo $! is geëxecuteerd. - Iain
Ja je hebt gelijk. Hiermee krijgt u de pid nadat myCommand is beëindigd. - Khaled
Verwijzen $! na && of ; zal je nooit de PID geven van het proces dat gestart is voor de linkerkant van het opdrachtscheidingsteken. $! is alleen ingesteld voor processen die asynchroon worden gestart (bijvoorbeeld meestal met & maar sommige shells hebben ook andere methodes). - Chris Johnsen
het is nuttig, en waarom niemand stemt me uit? goed werk al :) - temple


Dit is een beetje een hack-y antwoord en zal waarschijnlijk niet voor de meeste mensen werken. Het gaat ook om een ​​groot beveiligingsrisico, dus doe het niet, tenzij je zeker weet dat je veilig bent en dat de invoer gewist is en ... nou, je snapt het wel.

Compileer het kleine C-programma hier in een binair bestand genaamd start (of wat je maar wilt), voer dan je programma uit als ./start your-program-here arg0 arg1 arg2 ...

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char **argv)
{
    if (argc >= 2)
    {
        printf("%lu\n", (long unsigned) getpid());
        if (execvp(argv[1], &argv[1]) < 0)
        {
            perror(NULL);
            return 127;
        }
    }
    return 0;
}

Lang verhaal kort, dit zal de PID afdrukken naar stdout, laad dan je programma in het proces. Het moet nog steeds dezelfde PID hebben.


1