自定义命令执行器:C++中命令封装的深度探索(C/C++实现)

在现代软件开发中,执行系统命令是一项常见的需求,无论是自动化脚本、系统管理工具,还是需要调用外部程序的复杂应用程序,都离不开对系统命令的调用。然而,直接使用系统调用(如 execve)虽然简单,但存在诸多问题,例如安全性不足、灵活性差以及可维护性低等。为了克服这些问题,我们可以通过封装命令执行逻辑,设计一个自定义的命令执行器。本文将深入探讨如何在 C++ 中实现一个安全、灵活且易于管理的命令执行器。

一、背景与动机

在许多应用程序中,执行系统命令是一项常见需求。例如,自动化脚本、系统管理工具或需要调用外部程序的复杂应用程序。然而,直接使用系统调用(如 execve)存在以下问题:

安全性问题:直接拼接命令字符串可能导致命令注入攻击。
灵活性不足:系统调用通常需要手动管理参数和环境变量,容易出错。
可维护性差:直接调用系统调用的代码通常难以阅读和维护。
为了解决这些问题,我们设计了一个自定义的命令执行器包装器,通过封装命令执行逻辑,提供更安全、灵活且易于管理的接口。

二、设计与实现

1. 命令执行器类的设计

命令执行器的核心是一个 command 类,它封装了命令名称、参数列表和环境变量。以下是 command 类的主要设计:
类定义

class command
{
public:command(const std::string cmd, const std::vector<std::string>& arguments, const environ_map& envs = environ_map());command(const command&) = default;command(command&&) = default;command& operator=(const command&) = default;command& operator=(command&&) = default;~command() = default;void exec();private:std::string m_cmd;std::vector<std::string> m_arguments;environ_map m_envs;
};

构造函数
构造函数接受命令名称、参数列表和环境变量。其中,环境变量通过 environ_map 类型传递,这是一个自定义的环境变量映射类,支持从当前进程环境变量初始化。
执行逻辑
exec() 方法是命令执行的核心。它使用 execve 系统调用执行命令,同时处理参数和环境变量的转换。为了安全地管理动态分配的内存,我们使用 std::shared_ptr 来管理参数数组。

2. 参数和环境变量的处理

为了将参数列表和环境变量转换为 execve 所需的格式,我们设计了以下辅助函数:
参数转换

std::shared_ptr<char*> to_argv(const std::string& cmd, const std::vector<std::string>& vec)
{char **argv = new char*[vec.size() + 2];argv[0] = ::strdup(cmd.c_str());for(size_t i = 0 ; i < vec.size(); ++i)argv[i+1] = ::strdup(vec[i].c_str());argv[vec.size()+1] = nullptr;return std::shared_ptr<char*>(argv, argv_deleter);
}

环境变量转换
environ_map 类提供了一个 raw() 方法,将环境变量映射转换为 execve 所需的格式。它使用 动态分配内存,并通过自定义的 raw_environ_holder 类管理内存生命周期。

3. 环境变量管理

environ_map 类是一个封装了环境变量的映射类,支持从当前进程环境变量初始化,并提供安全的内存管理机制。以下是其主要实现:
环境变量映射

class environ_map : public std::map<std::string, std::string>
{
public:environ_map() = default;environ_map(const std::map<std::string, std::string>& map) : std::map<std::string, std::string>(map) {};environ_map(const environ_map&) = default;raw_environ_holder raw() const;static environ_map get_for_current_process();
};

从当前进程环境变量初始化

environ_map environ_map::get_for_current_process()
{environ_map result;int i = 0;while(environ[i]){std::string str(environ[i++]);size_t indx = str.find('=');if(indx == std::string::npos)throw std::runtime_error("Failed to parse env");result[str.substr(0, indx)] = str.substr(indx +1);}return result;
}

三、自定义命令执行器的包装器:实现与应用(C/C++实现)

展示如何使用自定义的命令执行器:
cpp复制

#include "command.h"
#include "environ_map.h"class command
{
public:command(const std::string cmd, const std::vector<std::string>& arguments, const environ_map& envs = environ_map());command(const command&) = default;command(command&&) = default;command& operator=(const command&) = default;command& operator=(command&&) = default;~command() = default;void exec();private:std::string m_cmd;std::vector<std::string> m_arguments;environ_map m_envs;
};...
class raw_environ_holder
{
public:raw_environ_holder() = delete;raw_environ_holder(const raw_environ_holder&) = delete;raw_environ_holder(raw_environ_holder&&);raw_environ_holder& operator=(const raw_environ_holder&) = delete;raw_environ_holder& operator=(raw_environ_holder&&);~raw_environ_holder();operator char**() { return ppenv;};private:friend class environ_map;explicit raw_environ_holder(char** ppenv) : ppenv(ppenv){};void destroy();char** ppenv;
};class environ_map : public std::map<std::string, std::string>
{
public:environ_map() = default;environ_map(const std::map<std::string, std::string>& map) : std::map<std::string, std::string>(map) {};environ_map(const environ_map&) = default;raw_environ_holder raw() const;static environ_map get_for_current_process();
};...
int main()
{// 获取当前进程的环境变量environ_map m = environ_map::get_for_current_process();for(const auto& p: m){std::cout << p.first << "=" << p.second << std::endl;}// 创建并执行命令command cmd("/bin/ls", std::vector<std::string>());cmd.exec();
}

我们首先获取当前进程的环境变量,然后创建一个 command 对象来执行 /bin/ls 命令。通过封装命令执行逻辑,代码更加清晰且易于维护。

If you need the complete source code, please add the WeChat number (c17865354792)

四、优势与总结

通过实现自定义命令执行器,我们可以更加灵活和安全地执行系统命令。上述实现不仅支持环境变量的设置和传递多个参数,还能够处理执行过程中的错误,并提供输出捕获的功能。这种封装方式使得命令执行变得更加简洁和易于维护,同时也提高了代码的安全性和可读性。未来,我们可以进一步扩展该执行器,添加更多的功能,如异步执行、超时控制等,以满足更多复杂的需求。

Welcome to follow WeChat official account【程序猿编码

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/8037.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

iic、spi以及uart

何为总线&#xff1f; 连接多个部件的信息传输线&#xff0c;是部件共享的传输介质 总线的作用&#xff1f; 实现数据传输&#xff0c;即模块之间的通信 总线如何分类&#xff1f; 根据总线连接的外设属于内部外设还是外部外设将总线可以分为片内总线和片外总线 可分为数…

Android WebView 中网页被劫持的原因及解决方案

文章目录 一、原因分析二、解决方案一览三、解决方案代码案例3.1 使用 HTTPS3.2 验证 URL3.3 禁用 JavaScript3.4 使用安全的 WebView 设置3.5 监控网络请求3.6 使用安全的 DNS 四、案例深入分析4.1 问题4.2 分析 五、结论 在 Android 应用开发中&#xff0c;WebView 是一个常用…

Linux——网络(udp)

文章目录 目录 文章目录 前言 一、upd函数及接口介绍 1. 创建套接字 - socket 函数 2. 绑定地址和端口 - bind 函数 3. 发送数据 - sendto 函数 4. 接收数据 - recvfrom 函数 5. 关闭套接字 - close 函数 二、代码示例 1.服务端 2.客户端 总结 前言 Linux——网络基础&#xf…

C语言学习强化

前言 数据的逻辑结构包括&#xff1a; 常见数据结构&#xff1a; 线性结构&#xff1a;数组、链表、队列、栈 树形结构&#xff1a;树、堆 图形结构&#xff1a;图 一、链表 链表是物理位置不连续&#xff0c;逻辑位置连续 链表的特点&#xff1a; 1.链表没有固定的长度…

【ArcGIS微课1000例】0141:提取多波段影像中的单个波段

文章目录 一、波段提取函数二、加载单波段导出问题描述:如下图所示,img格式的时序NDVI数据有24个波段。现在需要提取某一个波段,该怎样操作? 一、波段提取函数 首先加载多波段数据。点击【窗口】→【影像分析】。 选择需要处理的多波段影像,点击下方的【添加函数】。 在多…

css3 svg制作404页面动画效果HTML源码

源码介绍 css3 svg制作404页面动画效果HTML源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果 效果预览 源码如下 <!doctype html> <html> <head> <meta charse…

R语言学习笔记之高效数据操作

一、概要 数据操作是R语言的一大优势&#xff0c;用户可以利用基本包或者拓展包在R语言中进行复杂的数据操作&#xff0c;包括排序、更新、分组汇总等。R数据操作包&#xff1a;data.table和tidyfst两个扩展包。 data.table是当前R中处理数据最快的工具&#xff0c;可以实现快…

利用Qt5.15.2编写Android程序时遇到的问题及解决方法

文章目录 背景1.文件读写 背景 目前我用的是Qt5.15.2来编写Qt程序&#xff0c;环境的配置看我这篇文章【Qt5.15.2配置Android开发环境】 项目中的一些配置的截图&#xff1a; 1.文件读写 假如直接用 QFileDialog::getExistingDirectory来获取路径的话&#xff0c;会得到类…

【学术会议-第五届机械设计与仿真国际学术会议(MDS 2025) 】前端开发:技术与艺术的完美融合

重要信息 大会官网&#xff1a;www.icmds.net 大会时间&#xff1a;2025年02月28日-03月02日 大会地点&#xff1a;中国-大连 会议简介 2025年第五届机械设计与仿真国际学术会议&#xff08;MDS 2025) 将于2025年02月28-3月02日在中国大连召开。MDS 2025将围绕“机械设计”…

leetcode刷题记录(一百)——121. 买卖股票的最佳时机

&#xff08;一&#xff09;问题描述 121. 买卖股票的最佳时机 - 力扣&#xff08;LeetCode&#xff09;121. 买卖股票的最佳时机 - 给定一个数组 prices &#xff0c;它的第 i 个元素 prices[i] 表示一支给定股票第 i 天的价格。你只能选择 某一天 买入这只股票&#xff0c;并…

亲测有效!解决PyCharm下PyEMD安装报错 ModuleNotFoundError: No module named ‘PyEMD‘

解决PyCharm下PyEMD安装报错 PyEMD安装报错解决方案 PyEMD安装报错 PyCharm下通过右键自动安装PyEMD后运行报错ModuleNotFoundError: No module named ‘PyEMD’ 解决方案 通过PyCharm IDE python package搜索EMD-signal&#xff0c;选择版本后点击“install”执行安装

上海亚商投顾:沪指冲高回落 大金融板块全天强势 上海亚商投

上海亚商投顾前言&#xff1a;无惧大盘涨跌&#xff0c;解密龙虎榜资金&#xff0c;跟踪一线游资和机构资金动向&#xff0c;识别短期热点和强势个股。 一&#xff0e;市场情绪 市场全天冲高回落&#xff0c;深成指、创业板指午后翻绿。大金融板块全天强势&#xff0c;天茂集团…

【unity游戏开发之InputSystem——02】InputAction的使用介绍(基于unity6开发介绍)

文章目录 前言一、InputAction简介1、InputAction是什么&#xff1f;2、示例 二、监听事件started 、performed 、canceled1、启用输入检测2、操作监听相关3、关键参数 CallbackContext4、结果 三、InputAction参数相关1、点击齿轮1.1 Actions 动作&#xff08;1&#xff09;动…

ubuntu22安装issac gym记录

整体参考&#xff1a;https://blog.csdn.net/Yakusha/article/details/144306858 安装完成后的整体版本信息 ubuntu&#xff1a;22.04内核&#xff1a;6.8.0-51-generic显卡&#xff1a;NVIDIA GeForce RTX 3050 OEM显卡驱动&#xff1a;535.216.03cuda&#xff1a;12.2cudnn&…

Linux下Ubuntun系统报错find_package(BLAS REQUIRED)找不到

Linux下Ubuntun系统报错find_package(BLAS REQUIRED)找不到 这次在windows的WSL2中遇到了一个非常奇怪的错误&#xff0c;就是 CMake Error at /usr/share/cmake-3.22/Modules/FindPackageHandleStandardArgs.cmake:230 (message):Could NOT find BLAS (missing: BLAS_LIBRAR…

15天基础内容-5

day13 【String类、StringBuilder类】 主要内容 String类常用方法【重点】 String类案例【重点】 StringBuilder类【重点】 StringBuilder类常用方法【重点&#xff1a; append】 StringBuilder类案例【理解】 第一章String类 1.1 String类的判断方法 String类实现判断功能…

CommonAPI学习笔记-1

CommonAPI学习笔记-1 一. 整体结构 CommonAPI分为两层&#xff1a;核心层和绑定层&#xff0c;使用了Franca来描述服务接口的定义和部署&#xff0c;而Franca是一个用于定义和转换接口的框架&#xff08;https://franca.github.io/franca/&#xff09;。 ​ 核心层和通信中间…

单片机基础模块学习——DS18B20温度传感器芯片

不知道该往哪走的时候&#xff0c;就往前走。 一、DS18B20芯片原理图 该芯片共有三个引脚&#xff0c;分别为 GND——接地引脚DQ——数据通信引脚VDD——正电源 数据通信用到的是1-Wier协议 优点&#xff1a;占用端口少&#xff0c;电路设计方便 同时该协议要求通过上拉电阻…

Golang Gin系列-9:Gin 集成Swagger生成文档

文档一直是一项乏味的工作&#xff08;以我个人的拙见&#xff09;&#xff0c;但也是编码过程中最重要的任务之一。在本文中&#xff0c;我们将学习如何将Swagger规范与Gin框架集成。我们将实现JWT认证&#xff0c;请求体作为表单数据和JSON。这里唯一的先决条件是Gin服务器。…

< OS 有关 > 阿里云:轻量应用服务器 的使用 :轻量化 阿里云 vpm 主机

原因&#xff1a; &#xff1c; OS 有关 &#xff1e; 阿里云&#xff1a;轻量应用服务器 的使用 &#xff1a;从新开始 配置 SSH 主机名 DNS Tailscale 更新OS安装包 最主要是 清除阿里云客户端这个性能杀手-CSDN博客 防止 I/O 祸害系统 操作&#xff1a; 查看进程&#x…