2011-11-11 34 views
6

Tôi đang cố gắng chạy một chương trình có đầu vào tiêu chuẩn cụ thể. Tôi thành công bằng cách sử dụng một bộ mô tả tập tin của một tập tin, nơi có là những gì tôi muốn đưa vào stdin, nhưng tôi không viết trực tiếp trên stdin:execv * và viết bằng stdin

$cat input.test 
echo Hello 
$ 

Mã C:

int main(int argc, char **argv) 
{ 
    int fd = 0; 

    fd = open("input.test", O_CREAT); 
    close(STDIN_FILENO); 
    dup2(fd, STDIN_FILENO); 
    char *const args[] = { "bash", NULL }; 
    execvp("bash", args); 
} 

Đó hoạt động:

$./a.out 
Hello 
$ 

Nhưng nếu tôi cố gắng để viết trực tiếp trên STDIN sử dụng ống hiển thị chương trình gì và giữ chạy:

int main(int argc, char **argv) 
{ 
    int fds[2]; 

    pipe(fds); 
    close(STDIN_FILENO); 
    dup2(fds[1], STDIN_FILENO); 
    write(fds[1], "echo Hello;", 11); // Résults are identics with fds[0] 
    char *const args[] = { "bash", NULL }; 
    execvp("bash", args); 
} 

Cảm ơn sự giúp đỡ của bạn

Thân ái, Bastien.

EDIT Giải quyết vấn đề:

Cám ơn câu trả lời của bạn, đây mã mà hoạt động:

int main(void) 
{ 
    int fd[2]; 
    pid_t pid; 

    if (pipe(fd) < 0) 
     return EXIT_FAILURE; 

    if ((pid = fork()) < 0) 
     return EXIT_FAILURE; 
    else if (pid != 0) { /* father */ 
     close(fd[1]); 
     dup2(fd[0], STDIN_FILENO); 
     execlp("bash", "bash", (char *)0); 
    } else { /* son */ 
     close(fd[0]); 
     write(fd[1], "echo hello\n", 11); 
    } 

    return EXIT_SUCCESS; 
} 

Trả lời

4

Bạn cần phải xoay mặt đọc của đường ống thành stdin, không phải mặt ghi. (Và viết cho bên viết, rõ ràng.)

#include <unistd.h> 
#include <string.h> 
#include <stdio.h> 
int main(int argc, char **argv) 
{ 
    int fds[2]; 
    char cmd[] = "echo hello\nexit\n"; 

    pipe(fds); 
    close(STDIN_FILENO); 
    dup2(fds[0], STDIN_FILENO); 
    write(fds[1], cmd, strlen(cmd)); 
    char *const args[] = { "bash", NULL }; 
    execvp("bash", args); 
    return 0; 
} 

Đảm bảo bạn kiểm tra giá trị trả về của tất cả các chức năng đó, bạn sẽ không bao giờ quản lý mã của mình nếu không.

+0

tại sao bạn lại giảm bớt người khác?tìm hiểu tâm trí muốn biết :) – Will

+0

Tôi không biết tại sao tất cả các câu trả lời đều bị bỏ phiếu. – Mat

2

Khi bạn gọi đường ống, fd [0] là mở để đọc, và fd [1] là mở để viết. Bạn nên dup'ing stdin ở phía đọc (fd [0]) và ghi vào mặt ghi (fd [1]). Kiểm tra giá trị trả về của viết: có thể là -1.

Nhưng có vấn đề lớn hơn. Bạn không bao giờ đóng hai bên của đường ống. bash có thể chặn trên một đọc và không bao giờ làm bất cứ điều gì cho đến khi mặt viết của ống được đóng lại. Bạn nên đóng cả hai mặt của đường ống sau khi bạn dup và viết. (Hoặc đặt FD_CLOEXEC).

3

execv và bạn bè thay thế chương trình đang chạy hiện tại bằng chương trình được chỉ định; họ không trở lại - thực hiện tiếp tục ở đầu chương trình mới thay thế.

Vì vậy, những gì bạn thường làm là fork và, ở một trong các nhánh, hãy gọi execv. Sau đó bạn đọc và viết qua đường ống từ chương trình của bạn tiếp tục ở ngã ba khác. Thường có các chức năng popen để thực hiện điều này bằng hầu hết các ngôn ngữ; thật đáng buồn trong POSIX popen() được đọc hoặc viết hoàn toàn và không phải là hai chiều.

May mắn thay, tôi đã made, tested and published một chức năng popen3. Điều này cho phép bạn quay trở lại ba bộ mô tả tập tin - một cho stdin cho quá trình, và hai cho stdout và stderr. Sau đó bạn có thể sử dụng write() trên stdin.

0

Cũng lưu ý rằng thực hiện theo cách bạn làm, bạn phụ thuộc vào kích thước bộ đệm ống. Nếu bạn viết quá nhiều, viết sẽ bị chặn vì không có người đọc. Làm điều đó một cách đáng tin cậy, bạn nên fork(), làm exec trong child và ghi vào pipe trong parent. Bằng cách này, các đường ống sẽ có một người đọc và bạn sẽ có thể ghi càng nhiều dữ liệu như bạn muốn vào nó.