2

カスタム入力を使用して C++ からシェル スクリプトを呼び出そうとしています。私ができることは次のとおりです。

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

もちろん、 s をエスケープするのは非常に困難です。s を myscript.sh の stdin として使用する方法はありますか? つまり、次のようなものです。

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

2 に答える 2

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
于 2012-10-06T22:52:24.727 に答える
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 に切り替えて開始することをお勧めします。書き込みnを開始した直後にn+1を読み取ります。

于 2012-10-06T23:51:20.767 に答える