Bash 在简单程序上重新打开 tty
Bash reopen tty on simple program
#include <stdio.h>
#include <stdlib.h>
int main()
{
char buf[512];
fgets(buf, 512, stdin);
system("/bin/sh");
}
用cc main.c
编译
我想要一个单行命令,使该程序 运行 ls
无需等待用户输入。
# This does not work - it prints nothing
(echo ; echo ls) | ./a.out
# This does work if you type ls manually
(echo ; cat) | ./a.out
我在想:
- 为什么第一个示例不起作用?
- 在不更改源代码的情况下,什么命令可以使程序 运行
ls
?
我的问题是 shell 和 OS 不可知论,但我希望它至少能在 bash 4.
上工作
编辑:
在测试答案时,我发现这行得通。
(python -c "print ''" ; echo ls) | ./a.out
使用跟踪:
$ (python -c "print ''" ; echo ls) | strace ./a.out
...
read(0, "\n", 4096)
...
这也有效:
(echo ; sleep 0.1; echo ls) | ./a.out
似乎忽略了缓冲。这是由于竞争条件吗?
strace
显示发生了什么:
$ ( echo; echo ls; ) | strace ./foo
[...]
read(0, "\nls\n", 4096) = 4
[...]
clone(child_stack=NULL, flags=CLONE_PARENT_SETTID|SIGCHLD, parent_tidptr=0x7ffdefc88b9c) = 9680
换句话说,您的程序在运行您的 shell 之前读取了包含这两行的整个 4096 字节缓冲区。交互式很好,因为在读取发生时,管道缓冲区中只有一行,所以 over-reading 是不可能的。
您需要在第一个 \n
之后停止读取,唯一的方法是逐字节读取,直到您命中它。我不太了解 libc 是否支持这种功能,但这里直接使用 read
:
#include <unistd.h>
#include <stdlib.h>
int main()
{
char buf[1];
while((read(0, buf, 1)) == 1 && buf[0] != '\n');
system("/bin/sh");
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
char buf[512];
fgets(buf, 512, stdin);
system("/bin/sh");
}
用cc main.c
我想要一个单行命令,使该程序 运行 ls
无需等待用户输入。
# This does not work - it prints nothing
(echo ; echo ls) | ./a.out
# This does work if you type ls manually
(echo ; cat) | ./a.out
我在想:
- 为什么第一个示例不起作用?
- 在不更改源代码的情况下,什么命令可以使程序 运行
ls
?
我的问题是 shell 和 OS 不可知论,但我希望它至少能在 bash 4.
上工作编辑:
在测试答案时,我发现这行得通。
(python -c "print ''" ; echo ls) | ./a.out
使用跟踪:
$ (python -c "print ''" ; echo ls) | strace ./a.out
...
read(0, "\n", 4096)
...
这也有效:
(echo ; sleep 0.1; echo ls) | ./a.out
似乎忽略了缓冲。这是由于竞争条件吗?
strace
显示发生了什么:
$ ( echo; echo ls; ) | strace ./foo
[...]
read(0, "\nls\n", 4096) = 4
[...]
clone(child_stack=NULL, flags=CLONE_PARENT_SETTID|SIGCHLD, parent_tidptr=0x7ffdefc88b9c) = 9680
换句话说,您的程序在运行您的 shell 之前读取了包含这两行的整个 4096 字节缓冲区。交互式很好,因为在读取发生时,管道缓冲区中只有一行,所以 over-reading 是不可能的。
您需要在第一个 \n
之后停止读取,唯一的方法是逐字节读取,直到您命中它。我不太了解 libc 是否支持这种功能,但这里直接使用 read
:
#include <unistd.h>
#include <stdlib.h>
int main()
{
char buf[1];
while((read(0, buf, 1)) == 1 && buf[0] != '\n');
system("/bin/sh");
}