首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C 語言在 Linux 下執行 Shell 命令完整指南:system() 實戰與安全實踐

     編輯:關於C語言

核心 API:system() 函數

int system(const char *command) 是 C 標準庫提供的執行 Shell 命令接口。流程:fork() 子進程 → execl("/bin/sh", "sh", "-c", command, NULL) → 父進程 waitpid() 等待。返回值:Shell 退出碼(高 8 位),-1 表示 fork 失敗。

實戰案例:安全刪除指定文件


/**********************************************************************
 * 文件: TestShellCommand.c
 * 功能: 演示 C 語言執行 shell 命令刪除文件
 * 編譯: gcc -Wall -o TestShellCommand TestShellCommand.c
 **********************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>

int main() {
    char file_index[100] = {0};
    char file_dir[100] = "TestFile";  // 目標目錄
    char del_cmd[256] = {0};
    char *ext_ptr;
    int ret;

    printf("請輸入要刪除的文件索引(不含路徑):");
    if (scanf("%99s", file_index) != 1) {
        fprintf(stderr, "輸入讀取失敗\n");
        return 1;
    }

    // 判斷是否包含擴展名
    ext_ptr = strrchr(file_index, '.');
    if (ext_ptr == NULL) {
        // 無擴展名:刪除該前綴所有文件
        snprintf(del_cmd, sizeof(del_cmd), "rm -rf %s/%s.*", file_dir, file_index);
    } else {
        // 有擴展名:精確刪除
        snprintf(del_cmd, sizeof(del_cmd), "rm -rf %s/%s", file_dir, file_index);
    }

    printf("執行命令: %s\n", del_cmd);

    ret = system(del_cmd);
    if (ret == -1) {
        perror("system() 執行失敗");
        return 1;
    }

    // 解析退出碼:WEXITSTATUS 需包含 
    if (WEXITSTATUS(ret) != 0) {
        fprintf(stderr, "命令執行異常退出,碼=%d\n", WEXITSTATUS(ret));
        // 注意:rm -rf 文件不存在也返回 0,需自行判斷業務邏輯
    }

    printf("操作完成\n");
    return 0;
}

Makefile 示例


TestShellCommand: TestShellCommand.c
	gcc -Wall -g -o release/TestShellCommand TestShellCommand.c

clean:
	rm -f release/TestShellCommand *.o

目錄結構與運行演示


項目根目錄/
├── TestShellCommand.c
├── Makefile
└── release/
    ├── TestShellCommand      # 編譯產物
    └── TestFile/             # 待操作文件目錄
        ├── 123456.r
        └── 123457.txt

$ make
$ cd release
$ ./TestShellCommand
請輸入要刪除的文件索引(不含路徑):123456
執行命令: rm -rf TestFile/123456.*
$ ls TestFile/  # 123456.r 已刪除
123457.txt

安全性核心準則

風險對策
命令注入嚴格校驗輸入,禁止 ; & | $ ` 等字符,使用白名單
路徑遍歷規範化路徑,限制在允許目錄下(realpath + 前綴檢查)
權限提升最小權限運行,避免 setuid,必要時用 capabilities
競爭條件避免 TOCTOU,操作前後復查文件狀態
資源耗盡限制並發 system() 調用,超時控制

優於 system() 的替代方案

  1. fork + exec 系列:無 Shell 解析開銷,參數以數組傳遞,天然免疫注入,可精細控制文件描述符、環境變量、信號處理。
  2. popen():需捕獲命令輸出時使用,返回 FILE* 可流式讀取/寫入。
  3. 庫函數替代:刪除文件用 unlink()/remove(),目錄操作用 mkdir()/rmdir()/opendir(),完全繞過 Shell,更安全高效。
  4. 腳本語言嵌入:Lua/Python 嵌入器,複雜邏輯移至腳本層,C 層只暴露安全 API。

system() 返回值完整解析


#include <sys/wait.h>

int status = system(cmd);
if (status == -1) {
    // fork 失敗
} else if (WIFEXITED(status)) {
    int exit_code = WEXITSTATUS(status);  // 正常退出碼 0-255
} else if (WIFSIGNALED(status)) {
    int sig = WTERMSIG(status);  // 被信號終止
} else if (WIFSTOPPED(status)) {
    int sig = WSTOPSIG(status);  // 被信號停止
}

調試技巧

  • 命令構建後 打印完整命令字符串,便於手動複現
  • 開發階段在命令前加 set -x; 開啟 Shell 追蹤
  • 重要操作前後記錄審計日志:時間、用戶、命令、結果、耗時
  • 單元測試模擬各種輸入:空、超長、特殊字符、注入嘗試
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved