在特定脚本上通过execl运行时,为什么/ bin / sh挂起?

时间:2019-04-19 18:35:46

标签: c unix pipe sh

您能给我一些有关以下代码的想法吗?该代码运行,但不会退出。另一个字符串s="ls -1"效果很好。通过sh(1)运行shell片段也可以。

#include <unistd.h>
#include <string.h>

int
main(int argc, char *argv[])
{
    int fd[2];

    char *s = "ls -1 \"/usr/bin\" | while IFS= read -r fp\ndo\ncat <<- EOF\n\t$fp\nEOF\ndone;";
    //char *s = "ls -1";


    pipe(fd);

    switch(fork()) {
        case 0:
            close(fd[1]);
            dup2(fd[0], 0);
            execl("/bin/sh", "sh", NULL);
            close(fd[0]);
        break;
        default:
            close(fd[0]);
            write(fd[1], s, strlen(s) + 1);
            close(fd[1]);
        break;
    }

    return 0;
}

2 个答案:

答案 0 :(得分:3)

当我将评论转换为答案时,我测试了建议的更改,但并没有解决问题。一种有效的解决方法是在字符串的末尾添加; exit,即使这等同于作弊。但是,测试还表明它没有完成。好像ls没有终止。

我去了另一个终端,以查看lspipe97(您的代码的名字)的处理是否仍然存在;他们不是。

  • 尝试在“挂起”过程中输入ps

您应该获得正常的输出和提示。

由于父级不等待子级退出,因此提示在ls的输出中丢失了一个提示(该提示很长并且产生得很慢)。将输出重定向到/dev/null,您将看到提示。

  • 最好的解决方法可能是在父进程中添加一个wait()循环,这样它直到子进程之后才退出。
#include <sys/wait.h>

…
int corpse;
int status;
while ((corpse = wait(&status)) > 0)
    ;

在调试时,您可以打印corpsestatus,以便了解发生了什么情况。


我发现这个comment(没有其序言)仍然有效:

  

close(fd[0]);必须在execl()之前—记住,如果成功,execl()永不返回(仅在失败时返回)。可以说,您应该在exit(1);之后有一个错误报告和execl()或类似内容;此刻,您即使失败也报告成功。

Rule of Thumb注释本身是有效的,但实际上不适用于此代码-未关闭的管道描述符不会引起麻烦,即使没有关闭本应关闭的管道描述符也是如此。

答案 1 :(得分:1)

@WilliamPursell谢谢,您是对的。在这个示例中,我并没有专注于此。

@ user3629249我知道我没有进行正确的错误检查,谢谢!

@mosvy是OpenBSD,实际上是在Mac上运行的。

此版本有效:

#include <string.h>
#include <unistd.h>
#include <sys/wait.h>

int
main(int argc, char *argv[])
{
    int fd[2];

    char *s = "ls -1 '/usr/bin' | while IFS= read -r fp\ndo\ncat <<- EOF\n\t$fp\nEOF\ndone;";
    //char *s = "ls -1";


    pipe(fd);

    switch(fork()) {
        case 0:
            close(fd[1]);
            dup2(fd[0], 0);
            execl("/bin/sh", "sh", NULL);
            close(fd[0]);
        break;
        default:
            close(fd[0]);
            write(fd[1], s, strlen(s));
            close(fd[1]);
            wait(NULL);
        break;
    }

    return 0;
}

wait(2)做到了。我记得我曾经做过wait(2),但是我想我把close(1)的顺序弄错了,所以它阻塞了。

无论如何,问题已解决,谢谢!