将bash命令的终端响应读取到c++变量中

Reading terminal response to bash commands into c++ variable

本文关键字:c++ 变量 读取 响应 bash 命令 终端      更新时间:2023-10-16

有谁知道从bash命令读取终端输出到c++的方法吗?例如,在终端中输入"ls"将返回当前目录中的文件名,是否有办法将这些文件名导入到字符串或字符数组或其他东西中?我一直在研究fork(), exec()pipe()。我试图打开子(这里输入的系统命令)和父(这里读取的输出)之间的管道通信,但完全不成功。想法吗?

感谢Kerrek SB,我看到人们以各种方式使用popen(),但不确定这是否是要追求的路线。在文档的帮助下,并将其他人如何使用它的部分内容放在一起,我想出了这个。这就完成了我在文章中提出的问题:将命令"ls"中的终端响应导入到文件名向量中。但是,每个文件名都包含一个换行符,我隐式地删除了该换行符,将字符串文件中除最后一个元素外的所有元素都推回到vector中。

void currentDirFiles( vector<string> & filesAddress )
{ 
    FILE * pipe = popen( "ls", "r" );
    char buffer[1000];
    string file;
    vector<string> files;
    while ( fgets( buffer, sizeof( buffer ), pipe ) != NULL )
    {
        file = buffer;
        files.push_back( file.substr( 0, file.size() - 1 ) );
    }
    pclose( pipe );
    filesAddress.swap( files );
}

我正在尝试根据Mankarse的建议改编维基百科的RAII示例以满足我的需求,这就是我目前所拥有的。看起来我的方向对吗?我在这方面有什么明显的错误或误解吗?

 #include <cstdio>
// exceptions
class file_error { } ;
class open_error : public file_error { } ;
class close_error : public file_error { } ;
class read_error : public file_error { } ;
class TerminalPipe
{
   public:
       TerminalPipe():
           pipeHandle(std::popen("ls", "r"))
           {
               if( pipeHandle == NULL )
                   throw open_error() ;
           } 
    ~TerminalPipe()
    {
        std::pclose(pipeHandle) ;
    } 
    void currentDirFiles( vector<string> & filesAddress )
    {
       char buffer[1000];
       string file;
       vector<string> files;
       while ( fgets( buffer, sizeof( buffer ), pipeHandle ) != NULL )
       {
           if( std::ferror( pipeHandle ) ) 
               throw read_error();
           else
           {
               file = buffer;
               files.push_back( file.substr( 0, file.size() - 1 ) );
           }
       }
    }
    private:
        std::FILE* pipeHandle ;
        // copy and assignment not implemented; prevent their use by
        // declaring private.
        TerminalPipe( const file & ) ;
        TerminalPipe & operator=( const file & ) ;
};

然后这样调用它:

vector<string> dirFiles;
TerminalPipe pipe;    
pipe.currentDirFiles( dirFiles );

如果使用glibmm c++绑定,则可以执行以下操作

#include <glibmm.h>
#include <iostream>
#include <unistd.h>
void finished_process(int pid, int ret, Glib::RefPtr<Glib::MainLoop>& loop)
{
    loop->quit();
    std::cout << "Process finished: " << pid << "|" << ret <<
    std::endl;
}
int main()
{
    int stdout_fd, stdin_fd, stderr_fd, pid;
    Glib::ustring line;
    std::vector<std::string> command;
    Glib::init();
    command.push_back("ls");
    command.push_back("-l");
    command.push_back("|");
    command.push_back("grep");
    command.push_back("-i");
    command.push_back("my_file");
    try{
    Glib::spawn_async_with_pipes(".", command,
        Glib::SPAWN_SEARCH_PATH | Glib::SPAWN_DO_NOT_REAP_CHILD, sigc::slot<void>(),
        &pid, &stdin_fd, &stdout_fd, &stderr_fd);
    } catch(Glib::SpawnError &e){
    std::cout << "Error: " << e.what() << std::endl;
    return 0;
    }
    Glib::RefPtr<Glib::MainLoop> loop(Glib::MainLoop::create());
    Glib::RefPtr<Glib::MainContext> context = loop->get_context();
    context->signal_child_watch().connect(sigc::bind(sigc::ptr_fun(finished_process), loop),
                    pid);
    Glib::RefPtr<Glib::IOChannel> io = Glib::IOChannel::create_from_fd(stdout_fd);
    loop->run();
    while (io->read_line(line) != Glib::IO_STATUS_EOF){
    std::cout << line;
    }
    io->close();
    close(stdout_fd);
    std::cout << "Exit" << std::endl;
}

编译程序g++ -g -std=c++0x signal_child_watch_example.cc -o signal_child_watch_example `pkg-config --libs --cflags giomm-2.4`

在Ubuntu/Debian上,可以像下面这样安装glibmm库sudo apt-get install libglibmm-2.4-dev

注意在将来这个2.4版本号可能会改变。对上面的命令进行相应的修改。

来源:http://gtk.10911.n7.nabble.com/Glib-MainContext-signal-child-watch-is-not-working-td43517.html