c - shell脚本中的后台进程收到EOF
问题描述
很难解释这种行为,所以这里有一个可重现的例子(在 macOS 上测试)。
首先,我有以下 C 文件。细节并不重要,但我基本上使用read
系统调用从标准输入读取 16 个字节,或者直到遇到 EOF。请注意,这read
将在 EOF 上返回 0。
// test.c
#include <fcntl.h>
#include <stdio.h>
#include <unistd.h>
int main() {
char buf[1];
for (int i = 0; i < 16; i++) {
if (read(STDIN_FILENO, buf, 1) == 0) {
printf("EOF encountered! Number of bytes read: %d\n", i);
return 0;
}
}
printf("Read all 16 bytes\n");
return 0;
}
假设我将此文件编译成一个名为test
. 这是正在运行的程序:
$ echo 'sixteen bytes!!' | ./test
Read all 16 bytes
$ echo '' | ./test
EOF encountered! Number of bytes read: 1
$ ./test # Waits for user input
有道理吗?我什至可以使用最后一个命令并将其作为后台进程运行(尽管这没什么用):
$ ./test &
[1] 19204
[1] + suspended (tty input) ./test
假设我接受此命令并将其放入以下 shell 脚本(称为huh.sh
):
#!/bin/sh
./test &
当我运行这个 shell 脚本时,输出如下:
$ ./huh.sh
EOF encountered! Number of bytes read: 0
这意味着read
立即遇到 EOF,并且这只发生在 shell 脚本的上下文中。
如果我test
用另一个对 EOF 敏感的程序替换我会看到类似的行为。例如,如果我node &
直接在终端中运行,我将能够node
在ps
. 但是,如果我node &
在 shell 脚本中运行,它会立即退出。
有人可以解释一下吗?
解决方案
在 Bash 中,shell 脚本中的后台命令的运行方式与在终端键入的后台命令不同。请参阅Lists of Commands上的 Bash 手册,其中说:
如果命令被控制操作符'<code>&'终止,shell 会在子shell 中异步执行命令。这被称为在后台执行命令,这些被称为异步命令。shell 不等待命令完成,返回状态为 0(真)。当作业控制未激活时(请参阅作业控制),异步命令的标准输入在没有任何显式重定向的情况下从
/dev/null
.
作业控制在脚本中通常不活动。
请注意,正如Joseph Sible所指出的,Bash 中的这种行为与POSIX shell的要求是一致的。
推荐阅读
- java - Android 应用程序在打开 paytm 默认活动时崩溃。原因:java.lang.IllegalStateException:预期的 Android API 级别 21+ 但为 30
- java - 无法在模拟器上启动 android 应用程序
- javascript - 在数组的每一项末尾添加编号
- python - 如何获取在 django 的文件字段中上传的文件的原始名称
- javascript - 如何在多个条件下返回 True?
- java - Netflix DGS 中使用 ThreadLocal 的 Servlet 过滤器
- c++ - 具有 std::array 大小类型的派生模板类
- protocol-buffers - 是否可以在不编译 protobuf 编译器的情况下使用 Bazel?
- rust - 在 Rust 中将文件名转换为 URI
- twilio - Twilio 聊天机器人与网站的集成