बस शुरू की गई प्रक्रिया से कैसे पाएं


70

मैं प्रक्रिया शुरू करना चाहता हूं (जैसे। myCommand) और इसकी पिड प्राप्त करना (बाद में इसे मारने की अनुमति देना)।

मैंने नाम से पीएस और फिल्टर की कोशिश की, लेकिन मैं नामों से प्रक्रिया को अलग नहीं कर सकता

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

क्योंकि प्रक्रिया नाम अद्वितीय नहीं हैं।

मैं इस प्रक्रिया को चला सकता हूं:

myCommand &

मैंने पाया कि मैं इस पीआईडी ​​को प्राप्त कर सकता हूं:

echo $!

क्या कोई सरल उपाय है?

मैं एक लाइन कमांड के परिणामस्वरूप myCommand को निष्पादित करने और इसकी पीआईडी ​​प्राप्त करने में प्रसन्न होगा।

जवाबों:


77

इससे सरल और क्या हो सकता है echo $!? एक पंक्ति के रूप में:

myCommand & echo $!

धन्यवाद, इन कमांड को "&" के साथ विलय करने से मुझे बहुत मदद मिली।
राफालमैग 12

8
एक बैश स्क्रिप्ट में, एक लूप में जो प्रोग्राम शुरू करता है, $! सटीक नहीं है। कभी-कभी यह स्क्रिप्ट की खुद की पिड लौटा देता है, कभी-कभी स्क्रिप्ट से चलता है या स्क्रिप्ट से चलता है, विशेष रूप से इस परिदृश्य में लॉन्च की गई प्रक्रिया के लिए विशेष रूप से पीआईडी ​​पाने के लिए? pid = जैसा कुछ myprogramभयानक होगा

2
एनबी कि यह आपको &पिछली पंक्ति के रूप में कमांड शुरू करने की आवश्यकता है , अन्यथा गूंज मूल रूप से खाली है।
रोज़र

2
command & echo $!इस चरण में निष्पादन को मुक्त करने के लिए चर को असाइन करना :(
शशांक विवेक

26

एक छोटी स्क्रिप्ट में कमांड लपेटें

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

20

इसके चलने से पहले ही आप कमांड का उपयोग कर सकते हैं sh -cऔर execपीआईडी ​​प्राप्त कर सकते हैं ।

शुरू करने के लिए myCommand, ताकि उसका पीआईडी ​​मुद्रित होने से पहले ही प्रिंट हो जाए, आप उपयोग कर सकते हैं:

sh -c 'echo $$; exec myCommand'

यह काम किस प्रकार करता है:

यह एक नया शेल शुरू करता है, उस शेल के PID को प्रिंट करता है, और फिर शेल को आपके कमांड के साथ बदलने के लिए execबिलिन का उपयोग करता है , यह सुनिश्चित करता है कि इसमें समान PID हो। जब आपका शेल बिल्टिन के साथ एक कमांड चलाता है , तो आपका शेल वास्तव में वह कमांड बन रहा है , न कि खुद की एक नई कॉपी को फोर्क करने के अधिक सामान्य व्यवहार से, जिसका अपना अलग पीआईडी ​​है और जो तब कमांड बन जाता है।exec

मुझे लगता है कि यह अतुल्यकालिक निष्पादन (साथ &), नौकरी पर नियंत्रण, या खोज के साथ जुड़े विकल्पों की तुलना में बहुत सरल है ps। वे दृष्टिकोण ठीक हैं, लेकिन जब तक आपके पास उनका उपयोग करने के लिए एक विशिष्ट कारण नहीं है - उदाहरण के लिए, शायद कमांड पहले से ही चल रहा है, जिस स्थिति में उसके पीआईडी ​​की खोज या नौकरी पर नियंत्रण का उपयोग करना समझ में आता है - मैं पहले इस तरह से विचार करने का सुझाव देता हूं। (और मैं निश्चित रूप से इसे प्राप्त करने के लिए एक जटिल स्क्रिप्ट या अन्य कार्यक्रम लिखने पर विचार नहीं करूंगा)।

इस उत्तर में इस तकनीक का एक उदाहरण शामिल है।


उस आदेश के कुछ हिस्सों को कभी-कभी छोड़ा जा सकता है, लेकिन आमतौर पर नहीं।

यहां तक ​​कि अगर आप जिस शेल का उपयोग कर रहे हैं वह एक बॉर्न-शैली है और इस प्रकार execइन शब्दार्थों के साथ बिलिन का समर्थन करता है , तो आपको आमतौर पर इस उद्देश्य के लिए sh -cएक नई, अलग शेल प्रक्रिया बनाने के लिए उपयोग (या समकक्ष) से बचने की कोशिश नहीं करनी चाहिए , क्योंकि:

  • एक बार शेल बन myCommandजाने के बाद, बाद में कमांड चलाने के लिए कोई शेल नहीं है। sh -c 'echo $$; exec myCommand; fooके fooसाथ खुद को बदलने के बाद चलाने का प्रयास करने में सक्षम नहीं होगा myCommand। जब तक आप एक स्क्रिप्ट नहीं लिख रहे हैं जो इसे अपनी अंतिम कमांड के रूप में चलाती है, तो आप केवल echo $$; exec myCommandएक शेल में उपयोग नहीं कर सकते हैं जहां आप अन्य कमांड चला रहे हैं।
  • आप इसके लिए किसी सबशेल का उपयोग नहीं कर सकते । (echo $$; exec myCommand)तुलनात्मक रूप से अच्छे हो सकते हैं sh -c 'echo $$; exec myCommand', लेकिन जब आप $$अंदर भागते हैं ( ), तो यह मूल शेल के PID को देता है, न कि उपधारा के। लेकिन यह सबशेल का PID है जो नए कमांड का PID होगा। कुछ शैल उप-पीआईडी ​​खोजने के लिए अपने स्वयं के गैर-पोर्टेबल तंत्र प्रदान करते हैं, जिसे आप इसके लिए उपयोग कर सकते हैं। विशेष रूप से, बैश 4 में , (echo $BASHPID; exec myCommand)काम करता है।

अंत में, ध्यान दें कि कुछ गोले एक ऑप्टिमाइज़ेशन करेंगे जहाँ वे एक कमांड चलाते हैं जैसे कि exec(अर्थात, वे पहले फोर्किंग करते हैं) जब यह ज्ञात होता है कि शेल को बाद में कुछ भी करने की आवश्यकता नहीं होगी। कुछ गोले इसे कभी भी करने की कोशिश करते हैं, इसे चलाया जाना अंतिम आदेश है, जबकि अन्य केवल तभी करेंगे जब कमांड के पहले या बाद में कोई अन्य कमांड नहीं हैं, और अन्य इसे बिल्कुल नहीं करेंगे। प्रभाव अगर आपके लिखने के लिए भूल जाते हैं कि है execऔर बस का उपयोग sh -c 'echo $$; myCommand'तो यह होगा कभी कभी पर आप सही पीआईडी देना कुछ के साथ सिस्टम कुछ गोले। मैं इस तरह के व्यवहार पर भरोसा करने के खिलाफ सलाह देता हूं , और इसके बजाय हमेशा execजब आप की आवश्यकता होती है तब शामिल करते हैं।


इससे पहले कि मैं चला सकता हूं myCommand, मुझे अपनी बैश स्क्रिप्ट में कई पर्यावरण चर सेट करने होंगे। क्या ये उस वातावरण तक ले जाएंगे जिसमें execकमांड चल रही है?
user5359531

ऐसा लगता है कि मेरा वातावरण execकमान संभाल रहा है । हालाँकि, myCommandअन्य प्रक्रियाओं को शुरू करने पर यह दृष्टिकोण काम नहीं करता है, जो आप के साथ काम करने की आवश्यकता है; जब मैं जारी एक kill -INT <pid>जहां pidइस तरह से प्राप्त किया गया था, संकेत उप प्रक्रियाओं तक नहीं पहुंचता द्वारा शुरू किया myCommand, जबकि अगर मैं चलाने के myCommand वर्तमान सत्र और Ctrl + C में, संकेत सही ढंग से प्रचार-प्रसार।
user5359531

1
मैं यह करने की कोशिश की, लेकिन myCommand प्रक्रिया के पीआईडी ​​गूंज $ $ + 1 से पिड उत्पादन लगता है। क्या मुझसे कुछ ग़लत हो रहा है?
crobar

मेरी आज्ञा कुछ इस प्रकार है:sh -c 'echo $$; exec /usr/local/bin/mbdyn -f "input.file" -o "/path/to/outputdir" > "command_output.txt" 2>&1 &'
crobar

7

मैं किसी भी सरल समाधान के बारे में नहीं जानता, लेकिन $ का उपयोग नहीं कर रहा हूँ! काफी है? आप हमेशा किसी अन्य चर के मान को असाइन कर सकते हैं यदि आपको बाद में इसकी आवश्यकता है, जैसा कि दूसरों द्वारा कहा गया है।

साइड नोट के रूप में, पीएस से पाइपिंग के बजाय आप उपयोग कर सकते हैं pgrepया pidof


5

फ़ाइल में पिड को पंजीकृत करने के बाद बैश स्क्रिप्ट से निष्पादन का उपयोग करें:

उदाहरण:

मान लें कि आपके पास एक स्क्रिप्ट है जिसका नाम "हमेशा के लिए" है जिसे आप args p1, P2, p3 के साथ चलाना चाहते हैं

हमेशा के लिए। स्रोत:

#!/bin/sh

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

एक रीपर बनाएँ।

#!/bin/sh

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

हमेशा के लिए चलाएं।

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

हमेशा के लिए। वह एक पंक्ति को लॉग करने के अलावा और कुछ नहीं करता है प्रत्येक 5 सेकंड में syslog

अब आपके पास /var/run/forever.sh.pid में pid है

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

और हमेशा के लिए.शोक चल रहा है। syslog grep:

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

आप इसे प्रक्रिया तालिका में देख सकते हैं:

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

3
ओह, और "oneliner": / बिन / श-सी 'गूंज $ $> / tmp / my.pid और& निष्पादित कार्यक्रम args' &
user237419

1
तर्कों में आंतरिक व्हाट्सएप को ठीक से संरक्षित करने के लिए, आपको exec "$@"इसके बजाय उपयोग करना चाहिए exec $*। तकनीकी रूप से आपको जिसे संरक्षित करने की आवश्यकता है वह व्हाट्सएप नहीं है बल्कि IFS शेल पैरामीटर में वर्णों की घटना है (जो अंतरिक्ष, टैब और न्यूलाइन में चूक करता है)।
क्रिस जॉन्सन

मुद्दा लेना। :)
user237419

धन्यवाद, मुझे $ $ पैरामीटर नहीं पता था। यह बहुत उपयोगी हो सकता है।
राफालमग

3

बाश शेल में एक विकल्प अंतर्निहित $!हो सकता jobs -pहै। कुछ मामलों में !में $!से पहले (या के बजाय) चर विस्तार खोल से व्याख्या हो जाता है, अनपेक्षित परिणाम के लिए अग्रणी।

यह, उदाहरण के लिए, काम नहीं करेगा:

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

जबकि यह होगा:

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

मुझे लगता है कि आपका मतलब ((आपका) और जॉब्स -p> / var / run / pidfile) था।
डोम

1

आप कुछ का उपयोग कर सकते हैं जैसे:

$ myCommand ; pid=$!

या

$ myCommand && pid=$!

दो आज्ञाओं का उपयोग ;कर जोड़ों या हो सकता है &&। दूसरे मामले में, पीआईडी ​​तभी सेट की जाएगी जब पहली कमांड सफल होगी। आप प्रक्रिया आईडी से प्राप्त कर सकते हैं $pid


3
ओपी पीआईडी ​​प्राप्त करना चाहता है ताकि वह इसे बाद में मार सके। ; और & $ $ गूंज से पहले बाहर निकलने के लिए मूल प्रक्रिया की आवश्यकता होती है! निष्पादित किया जाता है।
user9517

हाँ आप सही है। MyCommand समाप्त होने के बाद यह आपको पीड देगा।
खालिद

6
संदर्भित $!करने के बाद &&या ;आप पीआईडी देना कभी नहीं होगा की प्रक्रिया आदेश विभाजक के बाएं हाथ की ओर के लिए शुरू कर दिया। $!केवल अतुल्यकालिक रूप से शुरू की गई प्रक्रियाओं के लिए निर्धारित किया जाता है (जैसे आमतौर पर &लेकिन कुछ गोले अन्य तरीके भी होते हैं)।
क्रिस जॉन्सन

यह मददगार है, और कोई मुझे वोट क्यों नहीं देता? अच्छी नौकरी हालांकि :)
मंदिर

1

यह हैक-वाई उत्तर का एक सा है और संभवतः अधिकांश लोगों के लिए काम नहीं करेगा। यह एक बड़ा सुरक्षा जोखिम मेथिंक है, इसलिए इसे तब तक न करें जब तक कि आप सुनिश्चित न हों कि आप सुरक्षित रहेंगे और इनपुट सैनिटाइज्ड हैं और ... ठीक है, आपको यह विचार मिलता है।

यहां थोड़ा सी प्रोग्राम को बाइनरी start(या जो भी आप चाहते हैं) में संकलित करें , फिर अपना प्रोग्राम चलाएं./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;
}

लंबी कहानी छोटी, यह पीआईडी ​​को प्रिंट करेगा stdout, फिर अपने कार्यक्रम को प्रक्रिया में लोड करेगा। यह अभी भी एक ही पीआईडी ​​होना चाहिए।


मैं इस कोड द्वारा वापस किए गए PID नंबर को बैश वैरिएबल में कैसे रिकॉर्ड कर सकता हूं? मेरे लिए एक कारण स्पष्ट नहीं है, stdoutइस उदाहरण में दर्ज नहीं लगता है:RESULT="$(./start_and_get_pid.out echo yo)"; echo "$RESULT"
Tfb9

@ Tfb9: मैं ईमानदारी से अन्य दृष्टिकोणों में से एक की सिफारिश करूंगा; मैंने यह 2+ साल पहले लिखा था और यह अब तक प्रस्तुत किए गए हैकर / त्रुटि-प्रवण तरीकों में से एक है (या तो मुझे लगता है)।
1

नोट के लिए धन्यवाद। मुझे लगता है कि मैंने इसके साथ अपनी समस्या हल कर sleep 10 & PID_IS=$!; echo $PID_IS
ली
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.