execv*并以标准格式写入

execv*并以标准格式写入,c,unix,pipe,C,Unix,Pipe,我正在尝试使用特定的标准输入运行程序。我成功地使用了一个文件的文件描述符,其中有我想放在stdin中的内容,但我无法直接在stdin上写入: $cat input.test echo Hello $ 代码C: int main(int argc, char **argv) { int fd = 0; fd = open("input.test", O_CREAT); close(STDIN_FILENO); dup2(fd, STDIN_FILENO); char *co

我正在尝试使用特定的标准输入运行程序。我成功地使用了一个文件的文件描述符,其中有我想放在stdin中的内容,但我无法直接在stdin上写入:

$cat input.test
echo Hello
$
代码C:

int main(int argc, char **argv)
{
  int fd = 0;

  fd = open("input.test", O_CREAT);
  close(STDIN_FILENO);
  dup2(fd, STDIN_FILENO);
  char *const args[] = { "bash", NULL };
  execvp("bash", args);
}
这是有效的:

$./a.out
Hello
$
但是,如果我尝试使用管道直接在STDIN上写入,程序将不显示任何内容并保持运行:

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

  pipe(fds);
  close(STDIN_FILENO);
  dup2(fds[1], STDIN_FILENO);
  write(fds[1], "echo Hello;", 11); // Résults are identics with fds[0]
  char *const args[] = { "bash", NULL };
  execvp("bash", args);
}
谢谢你的帮助

诚恳地, 巴斯蒂安

已解决编辑问题:

感谢您的回答,下面是有效的代码:

int main(void)
{
    int fd[2];
    pid_t pid;

    if (pipe(fd) < 0)
        return EXIT_FAILURE;

    if ((pid = fork()) < 0)
        return EXIT_FAILURE;
    else if (pid != 0) { /* father */
        close(fd[1]);
        dup2(fd[0], STDIN_FILENO);
        execlp("bash", "bash", (char *)0);
    } else { /* son */
        close(fd[0]);
        write(fd[1], "echo hello\n", 11);
    }

    return EXIT_SUCCESS;
}
int main(无效)
{
int-fd[2];
pid_t pid;
如果(管道(fd)<0)
返回退出失败;
如果((pid=fork())<0)
返回退出失败;
如果(pid!=0){/*父*/
关闭(fd[1]);
dup2(fd[0],标准文件号);
execlp(“bash”,“bash”,“char*)0);
}else{/*子*/
关闭(fd[0]);
写入(fd[1],“echo hello\n”,11);
}
返回退出成功;
}

当您调用管道时,fd[0]打开用于读取,fd[1]打开用于写入。您应该在读取端(fd[0])复制stdin,并在写入端(fd[1])写入。检查write的返回值:可能是-1


但还有一个更大的问题。你永远不会关闭管道的任何一边。bash可能会阻塞读取,并且在管道的写入端关闭之前不会执行任何操作。您应该在复制和写入后关闭管道的两侧。(或设置FD_CLOEXEC)。

您需要将管道的读取端复制到
stdin
,而不是写入端。(显然,要写在写端。)

#包括
#包括
#包括
int main(int argc,字符**argv)
{
int-fds[2];
char cmd[]=“echo hello\nexit\n”;
管道(fds);
关闭(标准文件号);
dup2(fds[0],标准文件号);
写入(fds[1],cmd,strlen(cmd));
char*const args[]={“bash”,NULL};
execvp(“bash”,args);
返回0;
}

确保您检查了所有这些函数的返回值,但是,如果不检查,您将永远无法调试代码。

execv
,朋友们将用指定的程序替换当前正在运行的程序;它们不会返回-而是在新程序开始时继续执行

因此,您通常要做的是
fork
,并在其中一个fork中调用
execv
。然后,通过管道从另一个fork中继续读写程序。在大多数语言中,通常有
popen
函数来实现这一点;遗憾的是,在POSIX中,popen()是严格的读写操作,而不是双向的


幸运的是,我有一个
popen3
函数。这将返回三个文件描述符—一个用于进程的stdin,两个用于stdout和stderr。然后,您可以在stdin上使用write()。

还要注意,按照您的方式进行操作,取决于管道缓冲区的大小。如果您写得太多,写入将被阻止,因为没有读卡器。要可靠地执行此操作,应在子级中执行fork(),并在父级中写入管道。这样,管道将有一个读卡器,您将能够向其中写入任意数量的数据

#include <unistd.h>
#include <string.h>
#include <stdio.h>
int main(int argc, char **argv)
{
  int fds[2];
  char cmd[] = "echo hello\nexit\n";

  pipe(fds);
  close(STDIN_FILENO);
  dup2(fds[0], STDIN_FILENO);
  write(fds[1], cmd, strlen(cmd));
  char *const args[] = { "bash", NULL };
  execvp("bash", args);
  return 0;
}