2016-03-02 9 views
5

मैं एक खोल लागू कर रहा हूं।फोर्क() का उपयोग करके execvp() दो बार निष्पादित क्यों कर रहा है?

निर्देशिका बदलने के अलावा अन्य आदेश का प्रयास करते समय, execvp() रन, बच्चा समाप्त हो जाता है और एक नया बच्चा बनाया जाता है। जब मैं निर्देशिका बदलता हूं, तो बच्चा समाप्त नहीं होता है और एक नया बच्चा बनता है। सिवाय मैं Ctrl+D करने के लिए कार्यक्रम समाप्त करने के लिए दो बार राशि

for(;;) { 
    printf("bash: "); 
    parse(); 
    ... 
    pid_t pid = fork() 
    if (pid == 0) 
     if (!strcmp(line[0], "cd")) 
      if (!line[1]) (void) chdir(getenv("HOME")); 
      else (void) chdir(line[1]); 
     else execvp(line[0], line); 
    ... 
    if (pid > 0) { 
     while (pid == wait(NULL)); 
     printf("%d terminated.\n", pid); 
    } 
} 

cd ../; ls; रन सही ढंग से,: यहाँ मेरी कोड का एक नमूना है।

हालांकि, अगर मैं एक ही जानकारी (यानी mybash < chdirtest) पाइप करता हूं, तो यह सही ढंग से चलाता है, बच्चे को समाप्त करता है, मूल रूप से छोड़कर फिर से चलाता है, फिर अंतिम बच्चे को समाप्त करता है।

+3

जब आप चलाने के 'cd' (अधूरा) कोड शो के रूप में' आह्वान नहीं होंगे execvp':

ए (primitve) खोल चाहिए तरह दिखता है। इसके बजाय यह 'chdir' करेगा और फिर अगले' लूप पुनरावृत्ति 'को जारी रखेगा जो' फोर्क 'का आह्वान करेगा। यही कारण है कि पहली बाल प्रक्रिया 'सीडी' मामले के लिए बाहर नहीं निकलती है। – kaylum

+4

स्टैक ओवरफ़्लो में आपका स्वागत है। कृपया जल्द ही [के बारे में] पृष्ठ पढ़ें। मेरा तत्काल ध्यान यह है कि हमारे पास जवाब देने में सक्षम होने के लिए पर्याप्त जानकारी नहीं है - शैतान विवरण में है, और विवरण गुम हैं। हालांकि, @ कयालम समस्या का कम से कम हिस्सा है, और शायद मुख्य समस्या की पहचान की है। (मैं देखूंगा कि 'if (pid == 0)' के बाद सशर्त 'मुझे शुद्ध करते हैं - पर्याप्त ब्रेसिज़ नहीं, और' execvp() 'या' chdir() 'विफल होने पर कोई त्रुटि प्रबंधन नहीं होती है।) कृपया पढ़ें एक एमसीवीई ([एमसीवीई] बनाने के लिए) और फिर एक प्रदान करें। –

+1

@ kaylum मैं 'cd'' execvp() 'का आह्वान नहीं करना चाहता हूं। मैं चाहता हूं कि यह निर्देशिका को बदल दें, लूप वापस करें, फिर बताए गए मुद्दों के बिना अगली पंक्ति चलाएं। –

उत्तर

5

cd को बाल प्रक्रिया के माध्यम से नहीं बुलाया जाना चाहिए, खोल को स्वयं को अपनी वर्तमान निर्देशिका बदलनी चाहिए (यह एक आंतरिक कमांड की संपत्ति है: खोल की प्रक्रिया को संशोधित करें)।

for(;;) { 
    printf("bash: "); 
    parse(); 

    // realize internal commands (here "cd") 
    if (!strcmp(line[0], "cd")) { 
     if (!line[1]) (void) chdir(getenv("HOME")); 
     else (void) chdir(line[1]); 
     continue; // jump back to read another command 
    } 

    // realize external commands 
    pid_t pid = fork() 
    if (pid == 0) { 
     execvp(line[0], line); 
     exit(EXIT_FAILURE); // wrong exec 
    } 

    // synchro on child 
    if (pid > 0) { 
     while (pid == wait(NULL)); 
     printf("%d terminated.\n", pid); 
    } 
} 
संबंधित मुद्दे