2009-11-19 19 views
12

मैं सी में एक तरह से तलाश कर रहा हूँ प्रोग्राम के रूप में (यानी, कमांड लाइन से पुनर्निर्देशन का उपयोग नहीं) के लिए 'टी' कार्यक्षमता को लागू ऐसी है कि मेरी stdout दोनों stdout और एक लॉग फ़ाइल को जाता है। इसे मेरे कोड और सभी लिंक किए गए पुस्तकालयों के लिए काम करने की ज़रूरत है जो आउटपुट को आउटपुट करते हैं। इसे करने का कोई तरीका?मैं सी में प्रोग्रामेटिक रूप से 'टी' को कैसे कार्यान्वित कर सकता हूं?

+0

मैं का कारण है कि आप इस तरह के एक समाधान की आवश्यकता है एक अधिक विशिष्ट विस्तार से पूछ सकते हैं? क्या यह डिबगिंग पर सहेजना है ..? – lorenzog

उत्तर

7

आप टी कार्यक्रम popen() सकता है।

या आप कर सकते हैं fork() और पाइप stdout (एक वास्तविक लाइव कार्यक्रम मैंने लिखा से अनुकूलित, तो यह काम करता है!) इस जैसे एक बच्चे की प्रक्रिया के माध्यम:

void tee(const char* fname) { 
    int pipe_fd[2]; 
    check(pipe(pipe_fd)); 
    const pid_t pid = fork(); 
    check(pid); 
    if(!pid) { // our log child 
     close(pipe_fd[1]); // Close unused write end 
     FILE* logFile = fname? fopen(fname,"a"): NULL; 
     if(fname && !logFile) 
      fprintf(stderr,"cannot open log file \"%s\": %d (%s)\n",fname,errno,strerror(errno)); 
     char ch; 
     while(read(pipe_fd[0],&ch,1) > 0) { 
      //### any timestamp logic or whatever here 
      putchar(ch); 
      if(logFile) 
       fputc(ch,logFile); 
      if('\n'==ch) { 
       fflush(stdout); 
       if(logFile) 
        fflush(logFile); 
      } 
     } 
     putchar('\n'); 
     close(pipe_fd[0]); 
     if(logFile) 
      fclose(logFile); 
     exit(EXIT_SUCCESS); 
    } else { 
     close(pipe_fd[0]); // Close unused read end 
     // redirect stdout and stderr 
     dup2(pipe_fd[1],STDOUT_FILENO); 
     dup2(pipe_fd[1],STDERR_FILENO); 
     close(pipe_fd[1]); 
    } 
} 
+0

+1 कुछ भी नहीं मानने के लिए (उदाहरण के लिए, उपरोक्त कोड आसानी से फ़ाइल नाम के बजाय पहले से ही खुली फ़ाइल डिस्क्रिप्टर लेने के लिए एडाप्टर है) – Michael

+0

टीई ("टीई।txt "); सिस्टम (" ftp "); -> किसी भी विचार को stdin या stdout मुद्रित प्रतीत नहीं होता है? – Victor

+0

एक बार मैंने हटा दिया: अगर ('\ n' == ch) यह प्रिंट करता है। मुझे लगता है कि यह \ एन। अब टीई फ़ंक्शन अटक गया है जब तक कि मैं अंत में एंटर दबाता हूं। – Victor

-1

सी में ऐसा करने का कोई तुच्छ तरीका उपलब्ध नहीं है । मुझे लगता है सबसे आसान popen कॉल करने के लिए किया जाएगा (3), आदेश के रूप में टी और एक arument के रूप में वांछित लॉग फ़ाइल, साथ तो dup2 (2) नव खोला फ़ाइल * की फ़ाइल वर्णनकर्ता fd 1. पर

लेकिन यह थोड़ी बदसूरत दिखता है और मुझे कहना होगा कि मैंने यह कोशिश नहीं की है।

+0

इसे आजमाया और दौड़ की स्थिति का कारण बनता है। एक समस्या यह हो सकती है कि कभी-कभी टी प्रिंट प्रिंट हो। – PALEN

+0

@PALEN जैसा कि मैंने कहा, "अवांछित और बदसूरत लग रहा है"। यदि आप जीएनयू libc का उपयोग कर रहे हैं, तो अपनी खुद की फ़ाइल * जैसी वस्तुओं को बनाने के लिए एक कार्यक्षमता है और आप इसका उपयोग कर सकते हैं, लेकिन फिर आप असंगतता-भूमि में समाप्त हो जाएंगे। – Vatine

1

आप forkpty()exec() के साथ अपने पैरामीटर के साथ निगरानी कार्यक्रम निष्पादित करने के लिए उपयोग कर सकते हैं। forkpty() एक फ़ाइल डिस्क्रिप्टर देता है जो प्रोग्राम stdin और stdout पर रीडायरेक्ट किया जाता है। जो भी फाइल डिस्क्रिप्टर को लिखा गया है वह प्रोग्राम का इनपुट है। कार्यक्रम द्वारा लिखे गए जो भी फाइल डिस्क्रिप्टर से पढ़ा जा सकता है।

दूसरे भाग एक पाश में कार्यक्रम के उत्पादन पढ़ सकते हैं और यह एक फ़ाइल पर लिखने के लिए और भी stdout में इसे प्रिंट करने के लिए है।

उदाहरण:

pid = forkpty(&fd, NULL, NULL, NULL); 
if (pid<0) 
    return -1; 

if (!pid) /* Child */ 
{ 
execl("/bin/ping", "/bin/ping", "-c", "1", "-W", "1", "192.168.3.19", NULL); 
} 

/* Parent */ 
waitpid(pid, &status, 0); 
return WEXITSTATUS(status); 
+0

लेकिन इसका मतलब है कि किसी अन्य प्रोग्राम से अपना प्रोग्राम चलाना नहीं है यह संभवतः वह इससे बचना चाहता है अन्यथा वह टी का उपयोग करने के लिए तैयार होगा। – Benj

1

आप pipe(2) और dup2(2) का उपयोग एक फ़ाइल वर्णनकर्ता आप से पढ़ सकते हैं के लिए बाहर अपने मानक कनेक्ट करने के लिए कर सकता है। फिर आपके पास अलग-अलग थ्रेड मॉनिटरिंग हो सकती है जो फ़ाइल डिस्क्रिप्टर हो सकती है, जो इसे लॉग फ़ाइल में ले जाती है और मूल stdout (पाइप को जोड़ने से पहले dup2 द्वारा किसी अन्य दायरक्षेत्र में सहेजा गया एवे) लिखता है। लेकिन आपको पृष्ठभूमि धागे की आवश्यकता होगी।

दरअसल, मुझे लगता है कि वैटिन द्वारा सुझाए गए पॉपन टी विधि शायद सरल और सुरक्षित है (जब तक आपको लॉग फ़ाइल के साथ अतिरिक्त कोई भी करने की आवश्यकता नहीं है, जैसे टाइमस्टैम्पिंग या एन्कोडिंग या कुछ)।

5

"popen() टी" उत्तर सही थे। यहाँ एक उदाहरण प्रोग्राम है जो कि वास्तव में क्या करता है:

#include "stdio.h" 
#include "unistd.h" 

int main (int argc, const char * argv[]) 
{ 
    printf("pre-tee\n"); 

    if(dup2(fileno(popen("tee out.txt", "w")), STDOUT_FILENO) < 0) { 
     fprintf(stderr, "couldn't redirect output\n"); 
     return 1; 
    } 

    printf("post-tee\n"); 

    return 0; 
} 

स्पष्टीकरण:

popen() एक FILE* दिखाए, लेकिन dup2() एक फ़ाइल वर्णनकर्ता (FD), इसलिए fileno() एक fd को FILE* धर्मान्तरित की उम्मीद है। फिर dup2(..., STDOUT_FILENO)popen() से fd के साथ stdout को प्रतिस्थापित करने के लिए कहता है।

मतलब, आप एक बाल प्रक्रिया (popen) उत्पन्न करते हैं जो अपने सभी इनपुट को stdout और फ़ाइल में प्रतिलिपि बनाता है, फिर आप उस प्रक्रिया में अपना स्टडआउट पोर्ट करते हैं।

संबंधित मुद्दे

 संबंधित मुद्दे