برنامه نویسی

دستورات پوسته را با 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.

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا