2013-04-02 6 views
6

ile nasıl alırsınız Bir Linux komutunun çıkış dizesini ve ayrıca bir C++ programında komut çıkış durumunu almak istiyorum. Uygulamamda Linux komutları yürütüyorum. örneğinlinux komut çıkış dizesi ve çıktı durumunu C++

: Komut:

Rmdir abcd

Komut çıkış dizesi:

rmdir: Böyle bir dosya ya da dizin

: `abcd 'kaldırmak için başarısız

Command St ATUS:

bana bir komutun çıktısı dizeyi verir Linux çıkış durumunu verir fonksiyonunu system() ve işlevini popen() kullanarak çalıştı (komut başarısız olmuştur anlamına gelir) 1, ama ikisi de işlev bana hem çıkış dizesini hem de Linux komutunun çıkış durumunu verir.

+1

C++ kullanıyorsanız, soru neden C olarak etiketlenir? –

cevap

7

Çıkış dizgisi standart çıktıda veya standart hata tanımlayıcısında (sırasıyla 1 veya 2). Bu akışları yönlendirmek zorunda

Eğer (- POSIX pipe örneğin) onları okuyabileceği bir yere, ( dup ve dup2 fonksiyonu bakmak).

int pd[2]; 
int retValue; 
char buffer[MAXBUF] = {0}; 
pipe(pd); 
dup2(pd[1],1); 
retValue = system("your command"); 
read(pd[0], buffer, MAXBUF); 

Şimdi, sahip (bir kısmı) sizin tamponu içinde çıkışını ve retValue dönüş kodunu:

C ben böyle bir şey yapmak istiyorum.

Alternatif olarak, exec (yani execve) bir işlevi ve wait veya waitpid ile dönüş değeri elde edebilirsiniz.

Güncelleme: Bu yalnızca standart çıkışı yönlendirecektir. Standart hatayı yeniden yönlendirmek için dup2(pd[1],1) kullanın.

+0

Bunun işe yaradığından emin misiniz? Sistem() 'in kabuk süreci çıkana kadar geri dönmediğini düşündüm. Ayrıca, çocuğun çıktısı büyükse, "stdout" yazıyor, bir kilitlenme neden olabilir. Çocuğun çıktığı sırada boruda zaten olduğu için işe yaramazsa şaşırmayacağım, ama yine de kilitlenme bir sorun olabilir. – FatalError

+0

Peki, bu, çıktının boyutu, bir borunun boyutundan daha büyükse engellenebilir (makinemde varsayılan olarak 65536). Bu beklenen ise, fork + exec tercih edilen yoldur. Ama eğer değilse (yani, vaka biliniyorsa ve çıktı boyutu sınırlanmışsa), neden rahatsız oluyor? :) –

+0

Elbette, yeterince adil. İlginç strateji için +1 – FatalError

2

Maalesef, Linux'ta bunu yapmak için kolay ve basit bir yol yoktur. Here's bir örnek alt süreçlerin stdout/stderr/stdin'inin nasıl okunacağını/yazılacağını gösterir. Sadece :) Birlikte

Bu ikisini katılmak zorunda Şimdi

endID = waitpid(childID, &status, WNOHANG|WUNTRACED); 

: Eğer çıkış kodu almak istediğinizde

Ve (komple örnek verilen sayfanın alt kısmında verilmiştir) waitpid kullanmak zorunda

zamanda A ilgili ayrıntılı bilgi içeren (ALP) rogramming P inux L dvanced adında büyük bir serbest kitap var Mevcut sorun türleri here.

+0

Ve bu konularda http://advancedlinuxprogramming.com/ adresinde tam bir bölüm var –

+0

@BasileStarynkevitch ah, ALP, Bunu tamamen unutmuşum ... Cevap vermek için ekledim. – Vyktor

3

En basit çözüm, system'u kullanmak ve standart çıktı ve standart hatayı daha sonra silebileceğiniz geçici bir dosyaya yeniden yönlendirmektir.

0

popen sistem çağrısını kullanabilirsiniz, çıktıyı bir dosyaya yönlendirir ve dosyadan çıkışı bir dizeye yönlendirebilirsiniz. gibi: Daha fazla bilgi için

char buffer[MAXBUF] = {0}; 
    FILE *fd = popen("openssl version -v", "r"); 
    if (NULL == fd) 
    { 
     printf("Error in popen"); 
     return; 
    } 
    fread(buffer, MAXBUF, 1, fd); 
    printf("%s",buffer); 

    pclose(fd); 

popen için man sayfasını okuyun.

1

Yukarıda Piotr Zierhoffer yanıtı üzerinde inşa, burada sadece bunu yapar ve stdout ve özgün durumlarını stderr geri yükler bir işlev.

// Execute command <cmd>, put its output (stdout and stderr) in <output>, 
// and return its status 
int exec_command(string& cmd, string& output) { 
    // Save original stdout and stderr to enable restoring 
    int org_stdout = dup(1); 
    int org_stderr = dup(2); 

    int pd[2]; 
    pipe(pd); 

    // Make the read-end of the pipe non blocking, so if the command being 
    // executed has no output the read() call won't get stuck 
    int flags = fcntl(pd[0], F_GETFL); 
    flags |= O_NONBLOCK; 

    if(fcntl(pd[0], F_SETFL, flags) == -1) { 
     throw string("fcntl() failed"); 
    } 

    // Redirect stdout and stderr to the write-end of the pipe 
    dup2(pd[1], 1); 
    dup2(pd[1], 2); 
    int status = system(cmd.c_str()); 
    int buf_size = 1000; 
    char buf[buf_size]; 

    // Read from read-end of the pipe 
    long num_bytes = read(pd[0], buf, buf_size); 

    if(num_bytes > 0) { 
     output.clear(); 
     output.append(buf, num_bytes); 
    } 

    // Restore stdout and stderr and release the org* descriptors 
    dup2(org_stdout, 1); 
    dup2(org_stderr, 2); 
    close(org_stdout); 
    close(org_stderr); 

    return status; 
}