2010-04-16 15 views
5

मैं सी ++ में एक प्रोग्राम लिख रहा हूं जो लिनक्स ओएस पर मौजूदा निर्देशिका में सभी फ़ाइलों के लिए कुछ विशेष उपचार करता है।सी/सी ++ में प्रोग्राम के अंदर सिस्टम कॉल के आउटपुट को रीडायरेक्ट कैसे करें?

तो मैं सभी फ़ाइलों की सूची प्राप्त करने के लिए system("ls") जैसे सिस्टम कॉल का उपयोग करने की सोच रहा था।

लेकिन मेरे प्रोग्राम के अंदर इसे कैसे स्टोर किया जाए? (कैसे ls के उत्पादन अनुप्रेषित के एक स्ट्रिंग है कि मैं कार्यक्रम में घोषित कहना जाने के लिए करने के लिए)

धन्यवाद

उत्तर

7

मैं सुझाव है कि आप ls के लिए बाहर फोन नहीं है - काम ठीक से करते हैं, opendir/readdir/closedir का उपयोग कर सीधे पढ़ने के लिए निर्देशिका।

कोड उदाहरण, प्रिंट निर्देशिका प्रविष्टियों:

// $ gcc *.c && ./a.out 
#include <stdlib.h> // NULL 
#include <stdio.h> 
#include <dirent.h> 

int main(int argc, char* argv[]) { 
    const char* path = argc <= 1 ? "." : argv[1]; 

    DIR* d = opendir(path); 
    if (d == NULL) return EXIT_FAILURE; 

    for(struct dirent *de = NULL; (de = readdir(d)) != NULL;) 
    printf("%s/%s\n", path, de->d_name); 

    closedir(d); 
    return 0; 
} 
+0

@ जेएफ। सेबेस्टियन - धन्यवाद। –

+2

ध्यान रखें कि आपको बहु-थ्रेडेड प्रोग्राम में 'readdir' का उपयोग नहीं करना चाहिए। इसके बजाय आपको 'readdir_r' –

10

मुझे नहीं लगता कि आप उत्पादन को पढ़ने के लिए इस प्रणाली का उपयोग कर सकते हैं।

popen का उपयोग करने का प्रयास करें।

#include <stdio.h> 

    FILE *popen(const char *command, const char *type); 

    int pclose(FILE *stream); 

लेकिन, शायद आप ls के लिए ऐसा नहीं करना चाहते हैं। दो कारण हैं:

  • आप एक निर्देशिका लिस्टिंग, फ़ाइल सिस्टम API सीधे (readdir) का उपयोग करने के बजाय खोल आदेशों का उपयोग करते हैं और यह पार्स करने का प्राप्त करना चाहते हैं।
  • किसी ने मुझे हाल ही में blog post पर इंगित किया है कि यह बताते हुए कि ls आउटपुट पार्सिंग एक बुरा विचार क्यों है।
+1

का उपयोग करना चाहिए, मुझे लगता है कि यह समझाने के लिए एक अच्छा जोड़ा होगा कि वह 'ls' के लिए क्यों काम नहीं करेगा। –

+0

@ राफेलएसपी: मैंने एलएस का उपयोग न करने का वर्णन करने वाला एक और जवाब देखा था, लेकिन सिस्टम बनाम पॉपन सवाल का जवाब देना चाहता था। हालांकि प्वाइंट लिया गया, इसलिए मैंने एक बेहतर औचित्य जोड़ा है। – Stephen

+0

वाह, आपने यह सही किया है :-)। +2 अगर मैं कर सकता था ... –

0

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

+0

मैंने यूनिक्स/पॉज़िक्स पर्यावरण के लिए यहां एक और विस्तृत उदाहरण दिया है: https://blog.uxul.de/e?e=mt-160 – schoppenhauer

0

मैं 3 विकल्प देखें:

  1. system("ls > tempfile") करते हैं और उसके बाद से tempfile
  2. खुला एक पाइप pipe() का उपयोग कर, तो fork() का उपयोग एक नई प्रक्रिया अंडे ls के उत्पादन में पढ़ें। dup() पर कॉल करके बच्चे की प्रक्रिया में बंद फ़ाइल डिस्क्रिप्टर 2 और पाइप के विकल्प लिखने के अंत में। इसके बाद, बाल प्रक्रिया में exec("ls",...) पर कॉल करें। अंत में के आउटपुट को पैरेंट प्रक्रिया में पाइप से
  3. वर्तमान निर्देशिका में फ़ाइलों को गणना करने के लिए ls का उपयोग न करें। आपके प्रोग्राम में सही करने के लिए फ़ंक्शन हैं, यानी opendir(),readdir(),closedir

मैं अत्यधिक विकल्प की अनुशंसा 3.

0

या तो का उपयोग approiate ग निर्देशिका में फ़ाइलों को पढ़ने के लिए कहता है या आप अपने कार्यक्रम सामान्यीकरण तो यह इनपुट के रूप में फ़ाइलों की एक सूची लेता है और ls से उस सूची पहुंचाया ले अपने कार्यक्रम के लिए

> ls | yoursoftware 
4

यह करने के लिए एक आसान तरीका boost filesystem निर्देशिका iterator उपयोग करने के लिए है।या सिर्फ opendir/readdir/closir का उपयोग करें जैसा कि अन्य ने सुझाव दिया है। जिस तरह से आप आगे बढ़ रहे हैं उसके लिए कोई वास्तविक उलझन नहीं है।

कोड उदाहरण के लिए, एक निर्दिष्ट निर्देशिका में नियमित रूप से फ़ाइलों के लिए प्रिंट आकार:

// $ g++ listdir.cc -o listdir -lboost_filesystem && ./listdir 
#include <iostream> 
#include <boost/filesystem.hpp> 

int main(int argc, char* argv[]) { 
    using std::cout; 
    using namespace boost::filesystem; 

    std::string path(argc <= 1 ? "." : argv[1]); 

    if (is_directory(path)) { 
    for (directory_iterator itr(path); itr!=directory_iterator(); ++itr) { 
     cout << itr->path().filename() << ' '; // display filename only 
     if (is_regular_file(itr->status())) // display size for regular files 
     cout << " [" << file_size(itr->path()) << ']'; 
     cout << '\n'; 
    } 
    } 
    else cout << (exists(path) ? "Found: " : "Not found: ") << path << '\n'; 
} 
13

सर्वसम्मति "एलएस" का उपयोग नहीं करना प्रतीत होता है। हालांकि, किसी को भी है कि एक समारोह में रुचि रखता है यह करने के लिए के लिए:

/** 
* Execute a command and get the result. 
* 
* @param cmd - The system command to run. 
* @return The string command line output of the command. 
*/ 
string GetStdoutFromCommand(string cmd) { 

    string data; 
    FILE * stream; 
    const int max_buffer = 256; 
    char buffer[max_buffer]; 
    cmd.append(" 2>&1"); // Do we want STDERR? 

    stream = popen(cmd.c_str(), "r"); 
    if (stream) { 
     while (!feof(stream)) 
      if (fgets(buffer, max_buffer, stream) != NULL) data.append(buffer); 
     pclose(stream); 
    } 
    return data; 
} 
0

मैं # 2 pajton से लगता होगा सवाल करने के लिए सबसे उपयुक्त जवाब है।

यह "एलएस" एक कमांड का सबसे अच्छा उदाहरण नहीं है जिसके लिए आप इसका उपयोग करना चाहते हैं क्योंकि ऐसा करने के लिए अन्य देशी सी लाइब्रेरी फ़ंक्शंस उपलब्ध हैं, लेकिन ऐसे अन्य प्रोग्राम भी हैं जो आपके द्वारा आउटपुट उत्पन्न कर सकते हैं फ़ाइल लिखने/पढ़ने के बिना तुरंत प्रक्रिया करना चाहते हैं।

# 1 यूनिक्स/लिनक्स प्रकार प्रणाली पर भी अच्छा है जो एक कुशल रैम फ़ाइल सिस्टम लागू करता है जिसका उपयोग सिस्टम वैश्विक डेटा को पढ़ने/लिखने के लिए किया जा सकता है। लगभग सभी प्रणालियों पर यह काम पूरा करने के लिए वास्तव में एक अच्छा 'त्वरित' एन 'गंदे' तरीका है।

फिर से, अधिकांश प्रतिक्रिया देशी सी पुस्तकालयों का उपयोग करके निर्देशिका की सामग्री प्राप्त करने के बेहतर तरीके प्रदान करती हैं, लेकिन ऐसे कई उदाहरण हैं जहां पाइप(), कांटा(), डुप्ली(), exec(), सिस्टम() और popen() सिस्टम प्रक्रियाओं के साथ संचार के लिए उपयुक्त हैं।

0

फोर्क()/exec() और पाइप() सिस्टम कॉल का उपयोग यूनिक्स पर सबसे अच्छा सामान्य तरीका प्रतीत होता है। यह मानक आउटपुट और आवंटित कार्यक्रम की मानक त्रुटि धाराओं का सबसे आसान अलगाव की अनुमति देता है। कोई भी अपनी प्रक्रिया से बचने के लिए तैयार प्रक्रिया पर इंतजार कर सकता है और इसे काट सकता है। अंत में यदि कोई हो, तो प्रोग्राम किए गए प्रोग्राम के आउटपुट/त्रुटि से पढ़ने के लिए गैर-अवरुद्ध I/O का उपयोग कर सकते हैं।

सबसे बड़ी समस्या यह है कि विंडोज़ पर कुछ हासिल करने के लिए, आपको संभवतः कोड की कई सौ पंक्तियां लिखनी होंगी। मुझे एक बेहतर तरीका नहीं मिला और विंडोज संदर्भ में समस्या का अध्ययन नहीं किया है।

http://support.microsoft.com/kb/190351

+0

और पाइप के लिखने के अंत में बच्चे में आउटपुट रीडायरेक्ट करने के लिए डुप्लिकेट() सिस्टम कॉल। – CppNoob

+0

विंडोज़ पर अंतर केवल मामूली हैं। – CppNoob

+2

विंडोज़ पर, _CreatePipe_ का उपयोग करके दो विरासत योग्य अज्ञात पाइप बनाएं - एक स्टडआउट पढ़ने के लिए और एक आदेश जिसे आप बुलाएंगे। _CreateProcess_ का उपयोग करके बाल प्रक्रिया बनाकर कमांड को आमंत्रित करें और STARTUPINFO संरचना में इस बच्चे की प्रक्रिया में पाइप के लेखन-अंत हैंडल पास करें। stdout और stderr पाइप से पढ़ने के लिए अपने प्रोग्राम में पाइप के रीड-एंड हैंडल पर _ReadFile_ का उपयोग करें। अंत में, बच्चे प्रक्रिया को बाहर निकलने के लिए प्रतीक्षा करें और इसके प्रक्रिया संभाल पर CloseHandle को कॉल करने के लिए WaitForSingleObject का उपयोग करें। – CppNoob

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