是否可以通过管道实现命令替换?
Is it possible to implement command substitution via pipeline?
例如,我们有$(ls)
:
int pfd[2];
pipe(pfd);
switch (fork()) {
case 0:
close(pfd[0]);
dup2(pfd[1], 1 /*stdout*/);
exec('ls', 'ls');
case -1;
// Report the error...
break;
default;
break;
}
wait(nullptr); // Wait until the process is done (it is better to use the waitpid() version)
// And now we can read from pfd[0]
这段代码非常概念化,但我说得对吗?是否可以在子进程完成后从管道的写入端提取数据?剩下的就是将子字符串 ($(ls)
) 替换为另一个子字符串(ls
本身的结果)。有错请指正
即使 pfd[0]
是一个有效的文件描述符,它指向一个包含 ls
执行结果的缓冲区,我们如何安全地从中读取?
wait(nullptr);
这将暂停父进程,直到子进程终止。
子进程的标准输出连接到管道的写入端,管道的读取端在父进程中打开。
管道的内部缓冲区大小有限。如果子进程生成足够的输出,它将阻塞直到管道被读取。
但是父进程现在正在等待子进程终止后再做任何事情。这将导致死锁。
此外,看起来父进程仍然打开了管道的写端。如果父进程试图从它读取,并且它读取了所有内容,it 将阻塞,因为管道的写入端仍然打开(即使在子进程终止后)。
所以,不管你想做什么,父进程中管道的写端都要关闭。
从那时起,您“概念上”(如您所问)有多种选择。
你可以专注于从管道读取。当管道的写端关闭时,文件结束指示将通知您。子进程已终止,因此您现在可以 wait()
获取它的立即退出代码。
这可能是最常见的方法。其他方法也是可能的,比如阅读和关注 SIGPIPE
。或者在 Linux 上使用信号文件描述符来捕获 SIGPIPE
,以便通过从管道读取数据(通过 poll
或 select
)方便地进行多路复用.
请注意,如果子进程在写入管道后终止,并且父进程为子进程提供了 wait()
而未从管道读取,则在 wait()
returns 之后,可以从管道中读取未读数据。它仍然会在那里。但是,正如我所解释的,这是脆弱的,如果子进程产生足够的输出来堵塞整个管道,它就会崩溃。
从管道读取数据通常要简单得多,直到出现文件结束指示,然后在子进程之后进行清理。
例如,我们有$(ls)
:
int pfd[2];
pipe(pfd);
switch (fork()) {
case 0:
close(pfd[0]);
dup2(pfd[1], 1 /*stdout*/);
exec('ls', 'ls');
case -1;
// Report the error...
break;
default;
break;
}
wait(nullptr); // Wait until the process is done (it is better to use the waitpid() version)
// And now we can read from pfd[0]
这段代码非常概念化,但我说得对吗?是否可以在子进程完成后从管道的写入端提取数据?剩下的就是将子字符串 ($(ls)
) 替换为另一个子字符串(ls
本身的结果)。有错请指正
即使 pfd[0]
是一个有效的文件描述符,它指向一个包含 ls
执行结果的缓冲区,我们如何安全地从中读取?
wait(nullptr);
这将暂停父进程,直到子进程终止。
子进程的标准输出连接到管道的写入端,管道的读取端在父进程中打开。
管道的内部缓冲区大小有限。如果子进程生成足够的输出,它将阻塞直到管道被读取。
但是父进程现在正在等待子进程终止后再做任何事情。这将导致死锁。
此外,看起来父进程仍然打开了管道的写端。如果父进程试图从它读取,并且它读取了所有内容,it 将阻塞,因为管道的写入端仍然打开(即使在子进程终止后)。
所以,不管你想做什么,父进程中管道的写端都要关闭。
从那时起,您“概念上”(如您所问)有多种选择。
你可以专注于从管道读取。当管道的写端关闭时,文件结束指示将通知您。子进程已终止,因此您现在可以 wait()
获取它的立即退出代码。
这可能是最常见的方法。其他方法也是可能的,比如阅读和关注 SIGPIPE
。或者在 Linux 上使用信号文件描述符来捕获 SIGPIPE
,以便通过从管道读取数据(通过 poll
或 select
)方便地进行多路复用.
请注意,如果子进程在写入管道后终止,并且父进程为子进程提供了 wait()
而未从管道读取,则在 wait()
returns 之后,可以从管道中读取未读数据。它仍然会在那里。但是,正如我所解释的,这是脆弱的,如果子进程产生足够的输出来堵塞整个管道,它就会崩溃。
从管道读取数据通常要简单得多,直到出现文件结束指示,然后在子进程之后进行清理。