我有一个从 pipe(2( 的手册页复制的程序,经过修改,以便子分支一个 shell,父从 stdin 读取,将命令发送到要执行的子 shell。 这适用于第一个命令,但在运行该命令后,我收到一条消息,指出程序已停止,我返回到顶级 shell。
为什么会发生这种情况,我该如何阻止它?
信号(7( 说:
SIGTTIN P1990 Stop Terminal input for background process
但它不应该是一个后台进程,那么为什么它会停止呢?
接下来是一个终端会话,其中包含完整的源代码,gcc -Wall 的结果,并尝试运行该程序。 如您所见,我给出命令"日期",然后我被送回 到调用 shell,然后子 shell 执行"date"并显示输出,然后出现"exit"。 "fg"让我回到pipe_shell程序中,"正常运行时间"被发送到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: %sn", 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
尝试在没有bash
-i
选项的情况下运行程序,尽管您不会看到提示。
过于简化的 SIGTTIN 问题与read()
、控制 tty 和过程组有关。 有关详细信息,一个不错的起点是搜索词 google.com:linux SIGTTIN
;有一些文章深入研究了READ/TTY/PGRP。
要运行类似于小程序的交互式shell并可能解决大型程序的问题,您可以使用主/从伪设备。 有一个相关的库服务forkpty()
。 此外,还有一个名为script
的 UNIX/linux 实用程序,它将交互式 shell 会话记录到常规文件中;script
的源代码是读取器 + 写入器进程、主/从伪设备和交互式 shell 的一个很好的例子。