MochiuWiki : SUSE, EC, PCB
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
検索
個人用ツール
ログイン
Toggle dark mode
名前空間
ページ
議論
表示
閲覧
ソースを閲覧
履歴を表示
C++の基礎 - 外部コマンドのソースを表示
提供: MochiuWiki : SUSE, EC, PCB
←
C++の基礎 - 外部コマンド
あなたには「このページの編集」を行う権限がありません。理由は以下の通りです:
この操作は、次のグループのいずれかに属する利用者のみが実行できます:
管理者
、new-group。
このページのソースの閲覧やコピーができます。
== 概要 == 標準ライブラリのsystem関数、POSIXシステムのpopen関数、Windowsでは_popen関数を使用して外部コマンドを実行することができる。<br> <br> モダンなアプローチとしては、Boost.Processライブラリの使用が推奨される。<br> これは、プラットフォームに依存しない統一的なインターフェースを提供しており、同期・非同期の実行、標準入出力のリダイレクト、環境変数の制御、プロセス間通信等、高度な機能をサポートしている。<br> <br> パフォーマンスにおいては、system関数は新しいシェルプロセスを起動するため、オーバーヘッドが大きくなる傾向がある。<br> popen関数やBoost.Processライブラリは直接プロセスを制御できるため、より効率的な実行が可能である。<br> <br> クロスプラットフォーム開発においては、条件コンパイルを使用して適切な実装を選択、あるいは、Boost.Processライブラリのような抽象化層を利用することで、<br> プラットフォーム間の差異を吸収することができる。<br> <br> また、C++ 17以降では、std::filesystemライブラリを使用することにより、ファイルシステム操作に関連する多くのタスクを外部コマンドを使用せずに実行することが可能である。<br> これにより、よりセキュアで効率的なコードを記述することができる。<br> <br> <u>※注意</u><br> <u>セキュリティにおいて、外部コマンドを実行する場合はユーザ入力を直接使用することは避けるべきである。</u><br> <u>もし使用する場合は、必ず適切な入力検証とサニタイズを行う必要がある。</u><br> <u>実行するコマンドのパスを完全修飾パスで指定することにより、PATHインジェクション攻撃のリスクを軽減できる。</u><br> <br> <u>また、コマンドインジェクション攻撃のリスクにも注意が必要である。</u><br> <br><br> == system関数 == 最も一般的なアプローチは、<code>system</code>関数を使用することである。<br> これは、cstdlibヘッダに含まれており、シンプルな実装が可能である。<br> <br> <syntaxhighlight lang="c++"> #include <cstdlib> int main() { #ifdef _WIN32 system("dir"); // Windows #else system("ls -l"); // Linux #endif return 0; } </syntaxhighlight> <br> <u>しかし、system関数には重要な制限がある。</u><br> <u>それは、コマンドの出力を取得できないことやセキュリティ上のリスクが存在することである。</u><br> <br><br> == popen関数 / _popen関数 == より高度な制御が必要な場合は、<code>popen</code>関数 (POSIXシステム)、または、<code>_popen</code>関数 (Windows) を使用できる。<br> <br> <syntaxhighlight lang="c++"> #include <cstdio> #include <cstring> int main() { FILE* pipe = popen("ls -l", "r"); if (!pipe) return 1; char buffer[128]; std::string result = ""; while (fgets(buffer, sizeof(buffer), pipe) != NULL) { result += buffer; } pclose(pipe); } </syntaxhighlight> <br><br> == std::filesystemクラス == 最新のC++では、より安全で柔軟な方法として、<code>std::filesystem</code> (C++17以降) を使用することもできる。<br> これは直接的な外部コマンド実行ではないが、ファイルシステム操作に関しては優れた選択肢である。<br> <br><br> == Boost.Process == より高度な機能が必要な場合は、Boost.Process等のサードパーティ製ライブラリを使用することができる。<br> これは、非同期実行やプロセス間通信等の機能を提供している。<br> <br> Boost.Processを使用するには、BoostのSystemおよびFileSystemをインストールする必要がある。<br> # RHEL sudo dnf install boost1.78-system boost1.78-filesystem # SUSE sudo zypper install libboost_system1_75_0-devel libboost_filesystem1_75_0-devel <br> ==== 同期実行 ==== <syntaxhighlight lang="c++"> #include <iostream> #include <string> #include <vector> #include <boost/process.hpp> // 同期実行 void run_sync_command() { // 出力を格納する変数 std::string output; // パイプを使用してコマンドを実行して、出力を取得 boost::process::ipstream pipe_stream; boost::process::child c("/usr/bin/ls", boost::process::args({"-l"}), boost::process::std_out > pipe_stream); // 出力を1行ずつ読み取り std::string line; while (pipe_stream && std::getline(pipe_stream, line)) { output += line + "\n"; } // プロセスの終了を待機 c.wait(); std::cout << "Exit Code: " << c.exit_code() << std::endl; std::cout << "Output: " << output << std::endl; } int main() { try { run_sync_command(); } catch (const std::exception &e) { std::cerr << "Error: " << e.what() << std::endl; return -1; } return 0; } </syntaxhighlight> <br> ==== 非同期実行 ==== <syntaxhighlight lang="c++"> #include <iostream> #include <string> #include <vector> #include <boost/process.hpp> #include <boost/process/async.hpp> #include <boost/asio.hpp> // 非同期実行 void run_async_command() { // boost::asio::io_contextの作成 boost::asio::io_context io_context; // 出力を格納する変数 std::string output; // パイプを使用してコマンドを実行 boost::process::ipstream pipe_stream; boost::process::child c( boost::process::search_path("ls"), boost::process::args({"-l"}), boost::process::std_out > pipe_stream, io_context ); // 非同期読み取り用のバッファ std::vector<char> buf(4096); // 非同期読み取りの開始 boost::asio::async_read( pipe_stream, boost::asio::buffer(buf), [&](const boost::system::error_code& ec, std::size_t size) { if (!ec) { output.append(buf.begin(), buf.begin() + size); } } ); // 非同期処理の実行 io_context.run(); // プロセスの終了を待機 c.wait(); std::cout << "Exit Code: " << c.exit_code() << std::endl; std::cout << "Output: " << output << std::endl; } int main() { try { // 非同期実行 run_async_command(); } catch (const std::exception &e) { std::cerr << "Error: " << e.what() << std::endl; return -1; } } </syntaxhighlight> <br> ==== プロセス間通信 ==== Boost.Processを使用してプロセス間通信を行うことが可能である。<br> 子プロセスの標準入力、標準出力、標準エラー出力を通じて通信を行うことができる。<br> <br> 以下の例では、双方向通信 (親プロセスと子プロセス間で双方向のメッセージ交換)、および、非同期I/O (子プロセスからの出力を非同期で読み取る) を行っている。<br> <br> <syntaxhighlight lang="c++"> #include <iostream> #include <string> #include <thread> #include <chrono> #include <boost/process.hpp> #include <boost/asio.hpp> // 親プロセス class ProcessCommunicator { private: boost::asio::io_context io_context; boost::process::opstream child_stdin; boost::process::ipstream child_stdout; boost::process::child child_process; bool running; public: ProcessCommunicator() : running(false) {} // プロセスの起動 bool start(const std::string& command) { try { child_process = boost::process::child( command, boost::process::std_out > child_stdout, boost::process::std_in < child_stdin, io_context ); running = true; return true; } catch (const std::exception &e) { std::cerr << "Error starting process: " << e.what() << std::endl; return false; } } // 子プロセスにメッセージを送信 void send_message(const std::string &message) { if (!running) return; child_stdin << message << std::endl; child_stdin.flush(); } // 子プロセスからの出力を読み取る void read_output() { std::string line; while (running && std::getline(child_stdout, line)) { std::cout << "Parent received: " << line << std::endl; } } // プロセスの終了 void stop() { if (!running) return; send_message("exit"); child_process.wait(); running = false; } // プロセスが実行中かどうかを確認 bool is_running() const { return running && child_process.running(); } // デストラクタ ~ProcessCommunicator() { if (running) stop(); } }; int main() { ProcessCommunicator communicator; // 子プロセスを起動 if (!communicator.start("./Child")) { std::cerr << "Failed to start child process" << std::endl; return -1; } // 出力読み取り用のスレッドを起動 std::thread output_thread([&communicator]() { communicator.read_output(); }); // メインループ : ユーザ入力を子プロセスに送信 std::string input; std::cout << "Enter messages to send to child process (type 'exit' to quit):" << std::endl; while (std::getline(std::cin, input)) { if (input == "exit") break; communicator.send_message(input); } // プロセスを終了して、スレッドを待機 communicator.stop(); output_thread.join(); return 0; } </syntaxhighlight> <br> <syntaxhighlight lang="c++"> // Child.cppファイル (子プロセスとして実行するプログラム) #include <iostream> #include <string> int main() { std::string line; while (std::getline(std::cin, line)) { if (line == "exit") { std::cout << "Child process exiting..." << std::endl; break; } std::cout << "Child received: " << line << std::endl; std::cout << "Child processed: " << line << " (processed)" << std::endl; } return 0; } </syntaxhighlight> <br><br> {{#seo: |title={{PAGENAME}} : Exploring Electronics and SUSE Linux | MochiuWiki |keywords=MochiuWiki,Mochiu,Wiki,Mochiu Wiki,Electric Circuit,Electric,pcb,Mathematics,AVR,TI,STMicro,AVR,ATmega,MSP430,STM,Arduino,Xilinx,FPGA,Verilog,HDL,PinePhone,Pine Phone,Raspberry,Raspberry Pi,C,C++,C#,Qt,Qml,MFC,Shell,Bash,Zsh,Fish,SUSE,SLE,Suse Enterprise,Suse Linux,openSUSE,open SUSE,Leap,Linux,uCLnux,Podman,電気回路,電子回路,基板,プリント基板 |description={{PAGENAME}} - 電子回路とSUSE Linuxに関する情報 | This page is {{PAGENAME}} in our wiki about electronic circuits and SUSE Linux |image=/resources/assets/MochiuLogo_Single_Blue.png }} __FORCETOC__ [[カテゴリ:C++]]
C++の基礎 - 外部コマンド
に戻る。
案内
メインページ
最近の更新
おまかせ表示
MediaWiki についてのヘルプ
ツール
リンク元
関連ページの更新状況
特別ページ
ページ情報
We ask for
Donations
Collapse