دستورات پوسته را با Boost.Process اجرا کنید

امنیت ، قابلیت حمل و کنترل بیشتر از سیستم STD ::.
Boost.Process یک کتابخانه C ++ از Boost است که ایجاد و مدیریت فرآیندهای خارجی را آسانتر می کند و به شما امکان می دهد برنامه ها را اجرا کنید، خروجی ها را ضبط کنید و ورودی ها و خطاها را به طور کارآمد انجام دهید.
این یک رابط مدرن و انعطاف پذیر برای کار با فرآیندها ، محصور کردن جزئیات اجرای سیستم عامل ها و ارائه ویژگی هایی مانند اجرای ناهمزمان ، ارتباطات بین فرآیند (IPC) ، کنترل خروجی جریان و مدیریت زمان اجرا ارائه می دهد.
برای برنامه هایی که نیاز به تعامل با برنامه های خارجی یا اجرای دستورات سیستم به صورت کنترل شده و ایمن دارند ، ایده آل است.
Boost.Process برای ارائه یک جایگزین ایمن تر و انعطاف پذیر تر به std::system()
، که محدودیت های مختلفی دارد.
مقایسه با std::system
1 کنترل بیشتر بر روند
با boost::process
، شما می توانید:
- ضبط خروجی و ورودی (
std::system
این اجازه را مستقیماً اجازه نمی دهد). - متغیرهای محیط را تنظیم کنید.
- با فرآیندهای ناهمزمان کار کنید (
std::system
همیشه مسدود کننده است). - دایرکتوری های کار را مشخص کنید.
2 امنیت
std::system()
دستورات را از طریق a اجرا می کند پوسته، اگر در حال عبور از رشته های پویا باشید ، می تواند خطرناک باشد (خطر ابتلا به آن تزریق فرمان).
مثال خطرناک با std::system()
:
std::string user_input = "ls && rm -rf /"; // If injected, it can be catastrophic!
std::system(user_input.c_str());
با Boost.Process ، استدلال ها را به طور جداگانه تصویب می کنید و از مشکلات تزریق جلوگیری می کنید:
boost::process::child c("ls", "-l");
3 قابلیت حمل
-
std::system()
بستگی به پوسته سیستم دارد (cmd.exe
در ویندوز ،/bin/sh
در لینوکس). جدیدboost::process
در یک کار می کند قابل حمل راه ، بدون بستگی به پوسته زیرین.
4 اعدام غیر همزمان
-
std::system()
بلوک اعدام تا زمان خاتمه روند. - با تقویت ، می توانید فرایندها را به طور موازی بدون خراب کردن برنامه خود اجرا کنید:
boost::process::child c("long_task");
c.detach(); // Continue execution without waiting
5 دستکاری مستقیم ورودی/خروجی
با boost::process
، به راحتی می توانید ورودی/خروجی را هدایت کنید:
boost::process::ipstream out;
boost::process::child c("ls", boost::process::std_out > out);
std::string line; while (std::getline(out, line)) {
std::cout << line << std::endl;
}
با std::system()
، شما نیاز دارید لوله های دستی، که زحمتکش تر است.
چه موقع از هر کدام استفاده کنیم؟
✅ استفاده کنید تقویت در صورت نیاز قابلیت حمل ، ایمنی ، رسیدگی به I/O یا اجرای ناهمزمانبشر
⚠ استفاده کنید std::system()
فقط برای دستورات ساده و سریع جایی که ایمنی و کنترل مشکل نیستند.
نمونه های نصب و استفاده
برای نصب Boost.Process ، می توانید این مقاله را که ما تهیه کرده ایم دنبال کنید که هم از مدیران بسته استفاده می کند و هم بارگیری مستقیم از آدرس رسمی libboost: مفهوم ، نصب و استفاده از نمونه های کتابخانه Boost
مثال اساسی
این مثال نحوه اجرای ls
دستور با استفاده از BOOST.PROCESS:
مثال:
main.cpp
#include
#include
#include
namespace bp = boost::process;
int main() {
std::string output;
bp::ipstream pipe_stream; // Stream to capture the output
// Execute the "ls" command and redirect the output to pipe_stream
bp::child c("ls", bp::std_out > pipe_stream);
// Read the command output line by line
std::string line;
while (std::getline(pipe_stream, line)) {
std::cout << line << std::endl;
}
c.wait(); // Wait for the process to finish
return 0;
}
برای کامپایل ، شما به پرچم های اضافی احتیاج ندارید ، فقط به طور عادی کامپایل کنید و اجرا کنید:
g++ main.cpp
/a.out
اگر می خواهید از آن با آرگومان استفاده کنید ، خط را جایگزین کنید: bp::child
با مورد زیر:
//bp::child c("ls", bp::std_out > pipe_stream);
bp::child c("ls", "-l", "*.md", bp::std_out > pipe_stream);
در پوسته هایی که از کره زمین استفاده می کنند ممکن است هنگام استفاده از کارتهای وحشی مشکلی داشته باشید ، بنابراین از آن استفاده کنید bp::child
مثل این:
//bp::child c("ls", bp::std_out > pipe_stream);
bp::child c("/bin/sh", "-c", "ls -l *.md", bp::std_out > pipe_stream);
این لیست با جزئیات همه پرونده ها با پسوند Markdown در دایرکتوری که باینری را اجرا می کنید ، لیست می کند.
مثال دیگر
در صورت نصب آن بر روی سیستم خود ، این مثال نسخه GNU GCC را نشان می دهد ، اما با استفاده از خرابی مناسب تر برای استفاده.
#include
#include
#include
using namespace boost::process;
int main() {
ipstream pipe_stream;
std::string line;
try {
child c("/usr/bin/gcc", args = { "--version" }, std_out > pipe_stream);
while (pipe_stream && std::getline(pipe_stream, line)) {
std::cerr << line << std::endl;
}
c.wait();
// Check if the process was successful
if (c.exit_code() != 0) {
throw std::runtime_error("Process failed with error code: " + std::to_string(c.exit_code()));
}
} catch (const std::exception& e) {
std::cerr << "Failed to execute command: " << e.what() << std::endl;
return 1;
}
return 0;
}
ایده آل برای اطلاع از مسیر کامل برنامه است: /usr/bin/gcc
به جای فقط: gcc
، سعی کنید آن را تغییر دهید و فقط دستور برنامه را قرار دهید و ببینید که آیا خطایی خواهد داشت یا خیر.
محدودیت ها
دقیقاً مانند هر زیر فرآیند دیگر Lib ، چند دستور همانطور که انتظار می رفت کار نمی کنند ، زیرا ممکن است یک فرمان داخلی باشد ، مانند: history
بشر
ما قبلاً این مقاله را در این مقاله پوشش داده ایم: استفاده از C ++ به عنوان اسکریپت پوسته.
اگرچه می تواند تاریخ را نشان دهد ، اگر سعی کنید جلسه را پاک کنید ، مطمئناً کار نخواهد کرد. این اتفاق می افتد زیرا یک اجرایی جداگانه نیست. وقتی دویدید history -c
در یک زیرمجموعه ، در یک پوسته جدید قرار دارد که تاریخ جلسه اصلی شما را به اشتراک نمی گذارد.
این کد زیر منجر به یک عمل مورد انتظار نمی شود:
#include
#include
namespace bp = boost::process;
int main() {
std::string output;
bp::ipstream pipe_stream;
bp::child c("/bin/bash", "-c", "history -c && history -w", bp::std_out > pipe_stream);
std::string line;
while (std::getline(pipe_stream, line)) {
std::cout << line << std::endl;
}
c.wait();
return 0;
}
اگر هنوز می خواهید دستور را اجرا کنید ، کد صحیح است (همانطور که دیدیم می توان با استفاده از خطا بهبود یافت) ، اما از آنجا history -c
تولید نمی کند و تأثیر می گذارد فقط زیرمجموعهبشر
دستور تاریخ یک ویژگی داخلی پوسته است ، نه یک اجرایی جداگانه. وقتی دویدید
history -c
در یک زیرمجموعه ، در یک پوسته جدید قرار دارد که تاریخ جلسه اصلی شما را به اشتراک نمی گذارد.
برای اطلاعات بیشتر ، به مستندات مراجعه کنید: https://www.boost.org/doc/libs/1_84_0/doc/html/process/reference.html.