2015-05-23 11 views
6

के माध्यम से कमांड निष्पादित करते समय पाइप का उपयोग करके मैं एक नामहीन पाइप को कार्यान्वित करना चाहता हूं, और मुझे अपने किसी भी बच्चे में नहीं, मूल प्रक्रिया में आदेश निष्पादित करना होगा। प्रत्येक "-" एक पाइपलाइन ("|") के लिए एक कॉल के बराबर है, असाइनमेंट का हिस्सा भी मेरे पास यह कोड है। क्या कोई मुझे समझा सकता है कि यह क्यों काम नहीं करता है?माता-पिता

#include <stdio.h> 
#include <dirent.h> 
#include <sys/stat.h> 
#include <sys/types.h> 
#include <fcntl.h> // for open flags 
#include <time.h> // for time measurement 
#include <assert.h> 
#include <errno.h> 
#include <string.h> 
#include <unistd.h> 
#include <stdlib.h> 

void my_exec(char* cmd, char** argv) 
{ 
    int pipefd[2], f; 

    if (pipe(pipefd) < 0) 
     perror("pipe creation failed"); 

    f = fork(); 
    assert(f >= 0); 

    if (f == 0) { 
     // inside son process - connecting STDOUT to pipe write 
     if (dup2(pipefd[1], STDOUT_FILENO) < 0) 
      perror("dup2 failed"); 

     close(pipefd[0]); 
     close((int)stdout); 


    } else { 
     // inside parent process - connecting STDIN to pipe read and execute command with args 
     if (dup2(pipefd[0], STDIN_FILENO) < 0) 
      perror("dup2 failed"); 

     close(pipefd[1]); 
     close((int)stdin); 



if (execvp(cmd, argv) < 0) 
       perror("execvp failed"); 
     } 

} 

int main(int argc, char** argv) 
{ 
    assert(strcmp(argv[argc-1], "-")); 

    int i; 
    for (i = 1; i < argc; ++i) { 
     if (!strcmp(argv[i], "-")) { 
      argv[i] = NULL; 
      my_exec(argv[1], &argv[1]); 
      argv = &argv[i]; 
      argc -= i; 
      i = 0; 
     } 
    } 

    char* args[argc]; 
    args[argc-1] = NULL; 

    for (i = 1; i < argc; ++i) { 
     args[i-1] = argv[i]; 
    } 

    if (execvp(args[0], args) == -1) 
     perror("execvp failed"); 
    return; 
} 

आदेश:

./mypipe.o ls -l - grep "pipe" 

रिटर्न

total 24 
-rw-rw-r-- 1 omer omer 1463 May 23 19:38 mypipe.c 
-rwxrwxr-x 1 omer omer 7563 May 23 19:37 mypipe.o 
-rw-rw-rw- 1 omer omer 873 May 23 20:01 nice.c 
-rwxrwxr-x 1 omer omer 7417 May 23 19:44 nice.o 
-rw-rw-r-- 1 omer omer 0 May 23 17:10 try 

जो obviouslly पाइप फ्लॉप काम का मतलब है ... किसी भी विचार?

मुझे यकीन है कि np_exec को प्रत्येक कॉल एक भी बच्चे प्रक्रिया है कि बहस के बाकी पार्स करने के लिए जारी है शुरू होता है, जबकि मूल जनक प्रक्रिया निष्पादित करता दिए गए कार्यक्रम और तर्क (execvp का प्रयोग करके) बनाने की जरूरत है

संपादित करें: मुझे लगता है कि मुझे गलती मिली है: मैं पाइप के "पढ़ने-लिखने" सिरों को स्विच करता हूं।

सही समारोह:

void np_exec(char* cmd, char** argv) 
{ 
    int pipefd[2]; 
    int file; 

    if (pipe(pipefd) < 0) 
     perror("failed to create pipe"); 

    file = fork(); 
    assert(file >= 0); 

    if (file != 0) { 
     // inside parent process - connecting STDOUT to pipe write and execute command with args 
     if (dup2(pipefd[WRITE], STDOUT_FILENO) < 0) 
      perror("the function dup2 failed"); 

     close(pipefd[READ]); 
     close((int)stdout); 

     if (execvp(cmd, argv) < 0) 
      perror("the function execvp failed"); 

    } else { 
     // inside son process - connecting STDIN to pipe read 
     if (dup2(pipefd[READ], STDIN_FILENO) < 0) 
      perror("the function dup2 failed"); 

     close(pipefd[WRITE]); 
     close((int)stdin); 
    } 

} 
+0

प्रतीक्षा: परीक्षण किया है और काम कर रहे -

यहाँ कोड है? –

+0

मुझे यह सुनिश्चित करने की ज़रूरत है कि प्रत्येक कॉल np_exec एक एकल बाल प्रक्रिया शुरू करता है जो शेष तर्कों को पार्स करना जारी रखता है, जबकि मूल मूल प्रक्रिया निम्न प्रोग्राम और तर्क (execvp का उपयोग करके) निष्पादित करती है, – mike

+0

"जबकि मूल मूल प्रक्रिया निष्पादित होती है दिए गए कार्यक्रम और तर्क (execvp का उपयोग करके "मुझे नहीं लगता कि यह समझ में आता है: यदि अभिभावक प्रक्रिया execvp को कॉल करती है, तो उसे जो भी execvp कॉलिंग समाप्त हो जाएगा, उसे बदल दिया जाएगा। –

उत्तर

3

अद्यतन: तो, पता चला है मेरी मूल जवाब तरह से बंद आधार था। मैं पूरी तरह से समझ नहीं पाया कि अब तक आप क्या करना चाहते हैं।

आपका कोड अधिकतर सही है। यह एक बहुत ही सरल कारण के लिए काम नहीं करता है: गोले मानते हैं कि एक आदेश तब किया जाता है जब प्रक्रिया शुरू होती है।

मुझे एक उदाहरण के साथ व्याख्या करने की अनुमति दें। कल्पना करें कि आप ./mypipe a - b - c चलाते हैं।

यहाँ क्या हुड के नीचे होता है:

  • खोल कांटे mypipe निष्पादित करने के लिए एक प्रक्रिया है। यह तब होता है जब आपका प्रोग्राम निष्पादन शुरू करता है।

  • आपके प्रोग्राम कांटे, और माता-पिता exec(a) पर कॉल करते हैं। बच्चे अन्य तर्कों को पार्सिंग और पाइप निर्माण को संभालने में रखता है, जैसा कि यह माना जाता है।

तो, अब, इस बिंदु पर, आप माता-पिता चल रहे प्रोग्राम a है - जो, खोल की आँखों के लिए, प्रक्रिया है कि आदेश ./mypipe से मेल खाती है है, और आप एक बच्चे की प्रक्रिया है, जो शेल पूरी तरह उपेक्षित है, mypipe का काम कर रहा है - पाइप स्थापित करना, शेष कार्यक्रमों को निष्पादित करने के लिए पढ़ना आदि।

तो, अब आपके पास दौड़ की स्थिति है। चूंकि mypipe के पीछे की प्रक्रिया को a प्रोग्राम द्वारा प्रतिस्थापित किया गया है, जैसे ही a समाप्त हो जाता है, तो खोल मानता है कि आपके द्वारा टाइप किया गया आदेश किया जाता है (यानी, यह मानता है कि mypipe किया गया है), और प्रॉम्प्ट प्रिंट करता है, आपको उम्मीद है कि आप टाइप करें अगली कमांड

समस्या: a जल्दी समाप्त हो जाता है, और अपने बच्चे की प्रक्रिया अभी भी सभी कि अन्य कार्यक्रमों सूची पर जा रहा है और पाइप की स्थापना, इनपुट और आउटपुट पुनः निर्देशित है, और।इसलिए, उदाहरण के लिए, बाल प्रक्रिया अभी भी पाइप बनाने और अन्य कार्यक्रमों को पार्स करने पर काम कर रही है, जबकि उस समय तक a पहले से ही समाप्त हो चुका है और सब कुछ लिखा है - ओह!

आप इसे कैसे ठीक करते हैं? सरल: कमांड निष्पादन के क्रम को घुमाएं। अंतिम कमांड को निष्पादित करके प्रारंभ करें, फिर दूसरा दूसरा, आदि क्यों? क्योंकि यदि आप ऐसा करते हैं, तो माता-पिता पाइपलाइन पर अंतिम होंगे, इसलिए यह पाइप पढ़ने वाले चैनल में आने के लिए इनपुट की प्रतीक्षा कर रहा है। जब माता-पिता समाप्त हो जाते हैं, तो इसका मतलब है कि पाइपलाइन में अंतिम आदेश समाप्त हो गया है, जो वही है जो हम चाहते हैं। कोई रेस की स्थिति नहीं है, और खोल को यह सोचने में धोखा नहीं दिया जाता है कि हमारा आदेश वास्तव में नहीं होता है।

तो, कार्यक्रमों की सूची बाएं से दाएं की बजाय दाएं से बाएं से पार्स करने की बात है। इसके अलावा, यदि आप ऐसा करते हैं, तो आपको अब सहायक args सरणी की आवश्यकता नहीं होगी, जो कि बढ़िया है! है, जो आदेश आप माता-पिता में निष्पादित करने के लिए चाहते हैं, और जो आप के बच्चे में निष्पादित करने के लिए चाहते हो

#include <stdio.h> 
#include <dirent.h> 
#include <sys/stat.h> 
#include <sys/types.h> 
#include <fcntl.h> // for open flags 
#include <time.h> // for time measurement 
#include <assert.h> 
#include <errno.h> 
#include <string.h> 
#include <unistd.h> 
#include <stdlib.h> 

void my_exec(char* cmd, char** argv) 
{ 
    int pipefd[2], f; 

    if (pipe(pipefd) < 0) 
     perror("pipe creation failed"); 

    f = fork(); 
    assert(f >= 0); 

    if (f == 0) { 
     if (dup2(pipefd[1], STDOUT_FILENO) < 0) 
      perror("dup2 failed"); 

     close(pipefd[0]); 

    } else { 
     if (dup2(pipefd[0], STDIN_FILENO) < 0) 
      perror("dup2 failed"); 

     close(pipefd[1]); 

     if (execvp(cmd, argv) < 0) 
      perror("execvp failed"); 
     } 
} 

int main(int argc, char** argv) 
{ 
    assert(strcmp(argv[argc-1], "-")); 

    int i; 
    for (i = argc-1; i >= 1; i--) { 
     if (!strcmp(argv[i], "-")) { 
      argv[i] = NULL; 
      my_exec(argv[i+1], &argv[i+1]); 
      argc = i; 
     } 
    } 

    if (execvp(argv[0], &argv[1]) == -1) 
     perror("execvp failed"); 

    return 0; 
} 
+0

उत्तर देने के लिए धन्यवाद। यह कमांड निष्पादित करने के लिए और अधिक समझ में आता है बच्चे। हालांकि, इस कथन में मुझे माता-पिता के अंदर execvp() का उपयोग करने के लिए मजबूर किया गया है। – mike

+0

@ माइक आप हमेशा निष्पादित नहीं कर सकते() माता-पिता पर - क्या आप वाकई असाइनमेंट आवश्यकताओं को सही ढंग से समझ चुके हैं? पाइपलाइनों को मूल रूप से फोर्कड प्रक्रियाओं के सहयोग के एक समूह द्वारा निष्पादित करने के लिए डिज़ाइन किया गया है। एन आदेशों के साथ एक पाइप में, आपके पास हमेशा अन्य आदेशों को निष्पादित करने वाले मूल-चरण के लिए एन-1 फोर्क प्रक्रियाएं होंगी और अंतिम आदेश मूल परी द्वारा निष्पादित किया जा रहा है। इस तरह बैश और अन्य गोले इसे करते हैं। कौन सा प्रक्रिया निष्पादित करता है, इसका सटीक कार्यान्वयन विवरण क्या भिन्न हो सकता है, लेकिन यह सामान्य विचार है। –

+0

मुझे अभी भी एन -1 फोर्क प्रक्रियाएं चाहिए। लेकिन इस आचरण में, बस इतना जीवन बहुत आसान नहीं होगा, बच्चे और माता-पिता को "जगहों को घुमाने" की जरूरत है। बच्चा लूप जारी रखेगा, जबकि माता-पिता दिए गए आदेश – mike