我有一个从man页中复制的pipe(2)程序,经过修改后,子程序将fork掉一个shell,父程序从stdin读取命令,并将命令发送给子程序执行。 这对第一条命令来说是可行的,但是在那条命令运行之后,我收到了一条消息,说程序已经停止,我被返回到顶层的shell。
为什么会发生这种情况,我怎样才能停止它?
signal(7)说。
SIGTTIN P1990 Stop Terminal input for background process
但它不应该是一个后台进程,为什么要停止?
下面是一个终端会话,有完整的源代码,gcc -Wall的结果,并尝试运行程序。 正如你所看到的,我给了命令 "date",然后我被送回调用的shell,然后子shell执行 "date "并出现输出,然后出现一个 "exit"。 "fg "让我回到pipe_shell程序,"uptime "被发送到shell并运行,然后我可以做一个 "echo",然后我被送回顶层shell,再出现 "exit"。
sh-5.0$ cat pipe_shell.c
/* pipe_shell.c - learn about pipes
*
* Modified from the man page for pipe(2).
*/
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
int main(int argc, char *argv[])
{
int pipefd[2];
pid_t cpid;
if (argc != 1) {
fprintf(stderr, "Usage: %s\n", argv[0]);
exit(EXIT_FAILURE);
}
if (pipe(pipefd) == -1) {
perror("pipe");
exit(EXIT_FAILURE);
}
cpid = fork();
if (cpid == -1) {
perror("fork");
exit(EXIT_FAILURE);
}
if (cpid == 0) { // Child reads from pipe
close(pipefd[1]); // Close unused write end of pipe
close(STDIN_FILENO); // shut off standard input
dup2(pipefd[0], STDIN_FILENO); // pipe output is standard input
close(pipefd[0]); // close pipe output
execl("/bin/bash", "bash",
"--norc",
"-i",
(char *) 0);
perror("exec");
} else { // Parent writes to pipe
close(pipefd[0]); // Close unused read end
char line[256]; // we take input from keyboard
while ( fgets(line, 255, stdin) != NULL ) {
write(pipefd[1], line, strlen(line));
}
close(pipefd[1]); // Reader will see EOF
wait(NULL); // Wait for child
exit(EXIT_SUCCESS);
}
}
sh-5.0$ gcc -Wall pipe_shell.c -o pipe_shell
sh-5.0$ ./pipe_shell
bash-5.0$ date
date
[1]+ Stopped(SIGTTIN) ./pipe_shell
sh-5.0$ Wed 10 Jun 2020 12:16:28 PM EDT
bash-5.0$ exit
There are stopped jobs.
sh-5.0$ fg
./pipe_shell
uptime
uptime
12:16:52 up 154 days, 23:32, 5 users, load average: 0.04, 0.05, 0.07
bash-5.0$ echo "foo"
[1]+ Stopped(SIGTTIN) ./pipe_shell
echo "foo"
sh-5.0$ foo
bash-5.0$ exit
exit
试着运行你的程序而不使用 -i
的选择 bash
,虽然你不会看到提示。
过于简单的说,SIGTTIN的问题涉及到了 read()
,一个控制TTY,和过程组。 对于细节,一个不错的起点是google.com的搜索词。linux SIGTTIN
有一些文章深入研究了read tty pgrp.
要运行一个类似于你的小程序的交互式shell,并可能解决你的大程序的问题,你可以利用masterlave伪设备。 有一个相关的lib服务 forkpty()
. 另外,有一个UNIXlinux实用程序,名为 script
记录交互式shell会话到一个常规文件中的源码。script
是一个很好的例子,读者+写手进程,主从伪设备,以及一个交互式的外壳。