2013-04-02 159 views
6

Tôi muốn nhận chuỗi đầu ra của lệnh Linux cũng như tình trạng đầu ra lệnh trong chương trình C++. Tôi đang thực thi các lệnh Linux trong ứng dụng của mình.cách lấy chuỗi đầu ra lệnh linux và trạng thái đầu ra trong C++

ví dụ: Command:

rmdir abcd chuỗi đầu ra

Command:

rmdir: thất bại trong việc loại bỏ 'abcd': Không có tập tin hoặc thư mục

Command St những khoảng trống:

1 (Có nghĩa là lệnh đã được thất bại)

tôi đã cố gắng sử dụng Linux chức năng system() mang đến cho tình trạng đầu ra, và chức năng popen() mà mang lại cho tôi chuỗi sản phẩm của một lệnh, nhưng không phải chức năng cung cấp cho tôi cả hai chuỗi chuỗi đầu ra và trạng thái đầu ra của lệnh Linux.

+1

Tại sao câu hỏi được gắn thẻ C, nếu bạn đang sử dụng C++? –

Trả lời

7

Chuỗi đầu ra nằm trong đầu ra tiêu chuẩn hoặc bộ mô tả lỗi chuẩn (1 hoặc 2, tương ứng).

Bạn phải chuyển hướng các luồng này (hãy xem dupdup2 chức năng) đến một nơi, nơi bạn có thể đọc chúng (ví dụ - POSIX pipe).

Trong C Tôi muốn làm điều gì đó như thế này:

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

Bây giờ, bạn có (một phần của) đầu ra của bạn trong bộ đệm và mã trở lại trong retValue.

Hoặc, bạn có thể sử dụng hàm từ exec (ví dụ: execve) và nhận giá trị trả lại bằng wait hoặc waitpid.

Cập nhật: điều này sẽ chỉ chuyển hướng đầu ra tiêu chuẩn. Để chuyển hướng lỗi chuẩn, hãy sử dụng dup2(pd[1],1).

+0

Bạn có chắc chắn rằng nó hoạt động không? Tôi nghĩ rằng 'system()' không trở lại cho đến khi quá trình shell đã thoát. Ngoài ra, nếu đầu ra của đứa trẻ lớn thì chữ viết của nó thành 'stdout' có thể chặn, gây ra bế tắc. Tôi đoán tôi sẽ không ngạc nhiên nếu nó hoạt động như dữ liệu đã có trong đường ống khi đứa trẻ thoát, nhưng vẫn bế tắc có thể là một vấn đề. – FatalError

+0

Vâng, điều này có thể chặn nếu kích thước của đầu ra lớn hơn kích thước của một đường ống (65536 theo mặc định trên máy của tôi). Nếu điều này được mong đợi, sau đó fork + exec là cách ưa thích. Nhưng nếu không (ý tôi là, nếu trường hợp được biết và kích thước đầu ra bị giới hạn), thì tại sao lại bận tâm? :) –

+0

Chắc chắn, đủ công bằng. 1 cho chiến lược thú vị – FatalError

2

Thật không may, không có cách dễ dàng và đơn giản nào trong C trên Linux để thực hiện việc này. Here's một ví dụ về cách đọc/ghi stdout/stderr/stdin của quá trình con một cách chính xác.

Và khi bạn muốn nhận được mã lối ra bạn phải sử dụng waitpid (ví dụ hoàn chỉnh được cung cấp trên dưới cùng của trang cung cấp):

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

Bây giờ bạn chỉ cần kết hợp hai nội cùng nhau :)

Ngoài ra còn có một cuốn sách miễn phí tuyệt vời tên là một dvanced L inux P rogramming (ALP) có chứa thông tin chi tiết về se các loại vấn đề có sẵn here.

+0

Và có toàn bộ chương trong http://advancedlinuxprogramming.com/ về những vấn đề này –

+0

@BasileStarynkevitch ah, ALP, hoàn toàn quên mất điều đó ... Tôi đã thêm nó để trả lời. – Vyktor

3

Giải pháp đơn giản nhất là sử dụng system và để chuyển hướng lỗi chuẩn và lỗi chuẩn sang tệp tạm thời mà bạn có thể xóa sau này.

0

bạn có thể sử dụng popen cuộc gọi hệ thống, nó sẽ chuyển hướng đầu ra đến tệp và từ tệp mà bạn có thể chuyển hướng đầu ra đến một chuỗi. như:

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); 

Để biết thêm thông tin, đọc man trang cho popen.

1

Xây dựng trên Piotr Zierhoffer câu trả lời ở trên, đây là một chức năng thực hiện điều đó, đồng thời cũng khôi phục stdout và stderr trạng thái ban đầu của chúng.

// 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; 
} 
Các vấn đề liên quan