Bash重新开启简单程序

时间:2018-03-07 20:26:35

标签: c bash shell zsh bash4

#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

使用strace:

$ (python -c "print ''" ; echo ls) | strace ./a.out
...
read(0, "\n", 4096)
...

这也有效:

(echo ; sleep 0.1; echo ls) | ./a.out

似乎忽略了缓冲。这是因为竞争条件吗?

1 个答案:

答案 0 :(得分:1)

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字节的缓冲区,其中包含两行。交互式很好,因为在读取发生时,管道缓冲区中只有一行,因此无法读取。

您需要在第一个\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");
}