XXとしてる
2019年8月28日水曜日
C/C++の中でpopenで実行したコマンドの出力を色々触りたいときのメモ
Linuxには色々コマンドがあるけど、それをCとかC++とかで使うときはsystem()にコマンドを渡すとできる。 ```cpp #include
system("ls -a"); ``` が、コマンドの出力をそのままC/C++内で使うことはできない。 一応ファイルに出力するようにコマンドを実行すればそのファイルを開けばコマンドの出力結果を使用できるが、 できればsystem()を実行したらその出力をそのまま受け取りたい。受け取りたくない? というわけで色々調べたところ、popen()を使用すると出来るみたいだ。 [Man page of popen](https://linuxjm.osdn.jp/html/LDP_man-pages/man3/popen.3.html) ### ソースコード ```cpp #include
//for popen(), pclose(), fileno() #include
// for read() // ... 他色々インクルード // 実行したコマンドの出力を1行ごとに受け取り、predicateに渡す関数 void runProcess(const std::string& cmd, std::function
predicate) { // 読み込みフラグでpopen()を実行 auto pf = popen(cmd, "r"); if(pf == nullptr) { throw std::runtime_error("例外を投げる"); } // auto fd = fileno(pf); char c; std::string line; while(read(fd, &c, 1) > 0) { if(c == '\n') { predicate(line); line.clear(); } else { line += c; } } if (!line.empty()) { predicate(line); } pclose(pf); } ``` 使用例 ```cpp // 単純にlsコマンドの結果を出力する runProcess("ls", [](const string& line) { cout << line << endll; }); ``` 上のコードの説明としては、 - popen()には必ず読み込みフラグ('r')を指定する。 - popen()で開いた子プロセスのファイルディスクリプタを取得する - read()で子プロセスからの出力を読み込む - popen()で取得したFILE*はpclose()で必ず閉じること read()の周りのコードを見ると実行したプロセスの出力が1秒とか10秒とか何も出力されない間隔があったりするとうっかりループから抜け出てしまうのではないかと思ったのだが、上のコードでも問題なく動作する。 #### fileno()なんてあったんだ 実装中に悩んだことはread()で使用するファイルディスクリプタをどのように取得するのかが初めはわからなかったことである。 fileno()で取得するというとても簡単なことであったのが、fileno()の存在を知るまではFILEから直接取り出そうとか考えていたぐらいなので初めてのことはグダグダになるだなぁと。 それがわかれば、あとはすんなりと実装できた。 コード実装時には[pipe()のmanページ](https://linuxjm.osdn.jp/html/LDP_man-pages/man2/pipe.2.html)とか参考にしている。 (read()周りのループはそのまま持ってきている) ## 終わりに 今回はlddコマンドで実行ファイルが参照している共有ライブラリを検索するとき、参照している共有ライブラリが参照している共有ライブラリも一緒に検索出来たら便利かなと思ったのが、この記事を書くきっかけになった。
新しい投稿
前の投稿
ホーム
登録:
投稿 (Atom)