使用C ++将自定义stdin管道系统调用

时间:2012-10-06 22:46:35

标签: c++ file unix pipe stdin

我尝试使用自定义输入从C ++调用shell脚本。我能做的是:

void dostuff(string s) {
    system("echo " + s + " | myscript.sh");
    ...
}

当然,逃避是非常困难的。有没有办法可以使用s作为stdin的myscript.sh?即,像这样:

void dostuff(string s) {
    FILE *out = stringToFile(s);
    system("myscript.sh", out);
}

2 个答案:

答案 0 :(得分:2)

system调用后重新分配标准输入并恢复它的简单测试:

#include <cstdlib>     // system
#include <cstdio>      // perror
#include <unistd.h>    // dup2
#include <sys/types.h> // rest for open/close
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>

#include <iostream>

int redirect_input(const char* fname)
{
    int save_stdin = dup(0);

    int input = open(fname, O_RDONLY);

    if (!errno) dup2(input, 0);
    if (!errno) close(input);

    return save_stdin;
}

void restore_input(int saved_fd)
{
    close(0);
    if (!errno) dup2(saved_fd, 0);
    if (!errno) close(saved_fd);
}

int main()
{
    int save_stdin = redirect_input("test.cpp");

    if (errno)
    {
        perror("redirect_input");
    } else
    {
        system("./dummy.sh");
        restore_input(save_stdin);

        if (errno) perror("system/restore_input");
    }

    // proof that we can still copy original stdin to stdout now
    std::cout << std::cin.rdbuf() << std::flush;
}

很好地运作。我用一个简单的dummy.sh脚本测试了它,如下所示:

#!/bin/sh
/usr/bin/tail -n 3 | /usr/bin/rev

注意最后一行将标准输入转储到标准输出,因此您可以像

一样对其进行测试
./test <<< "hello world"

并期望以下输出:

won tuodts ot nidts lanigiro ypoc llits nac ew taht foorp //    
;hsulf::dts << )(fubdr.nic::dts << tuoc::dts    
}
hello world

答案 1 :(得分:0)

使用popen

void dostuff(const char* s) {
  FILE* f = fopen(s, "r");
  FILE* p = popen("myscript.sh", "w");
  char buf[4096];
  while (size_t n = fread(buf, 1, sizeof(buf), f))
    if (fwrite(buf, 1, n, p) < n)
      break;
  pclose(p);
}

您需要添加错误检查才能使其更加健壮。

请注意,我更喜欢const char*,因为它更灵活(适用于std::string之外的其他内容)并且匹配内部发生的事情。如果你真的喜欢std::string,那就这样做:

void dostuff(const std::string& s) {
    FILE* f = fopen(s.c_str(), "r");
    ⋮

另请注意,选择了4096字节的缓冲区,因为它与大多数系统上的页面大小相匹配。这不一定是最有效的方法,但对大多数用途来说都没问题。我已经发现32 KiB是我笔记本电脑上不科学的测试中的一个最佳点,所以你可能想玩,但如果你认真对待效率,你会想要切换到异步I / O,并开始在启动write n 后立即读取 n + 1