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

C語言實作自製命令列解析器 (非 system() 呼叫)

     編輯:C 語言問答

自製 Shell 核心流程

不呼叫 system() 或 cmd.exe,需自行實作:

  1. 讀取命令列:fgets(buf, sizeof(buf), stdin)。
  2. 詞法分析:依空白、引號、轉義字元切分成 argv[] 陣列。
  3. 內建命令:cd、exit、pwd 等直接在進程內處理。
  4. 外部命令:
    • Windows:CreateProcess()。
    • POSIX:fork() + execvp()。
  5. 等待/作業控制:WaitForSingleObject() / waitpid()。

Windows 極簡範例

#include <windows.h>
#include <stdio.h>
#include <string.h>

#define MAX_ARGS 64
#define BUFSIZE 1024

int main()
{
    char buf[BUFSIZE];
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi;

    while (1) {
        printf("mysh> ");
        if (!fgets(buf, BUFSIZE, stdin)) break;
        buf[strcspn(buf, "\n")] = '\0'; // 去換行
        if (!*buf) continue;

        // 簡易分割 (未處理引號/轉義)
        char *argv[MAX_ARGS] = {0};
        int argc = 0;
        for (char *p = strtok(buf, " "); p && argc < MAX_ARGS-1; p = strtok(NULL, " "))
            argv[argc++] = p;
        argv[argc] = NULL;

        if (strcmp(argv[0], "exit") == 0) break;
        if (strcmp(argv[0], "cd") == 0) {
            if (argc > 1) SetCurrentDirectoryA(argv[1]);
            continue;
        }

        // 建立命令列字串給 CreateProcess
        char cmdline[BUFSIZE] = "";
        for (int i = 0; i < argc; i++) {
            strcat(cmdline, argv[i]);
            if (i+1 < argc) strcat(cmdline, " ");
        }

        if (CreateProcessA(NULL, cmdline, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) {
            WaitForSingleObject(pi.hProcess, INFINITE);
            CloseHandle(pi.hProcess);
            CloseHandle(pi.hThread);
        } else {
            printf("命令執行失敗: %lu\n", GetLastError());
        }
    }
    return 0;
}

進階擴充方向

  • 支援管道 |、重導向 > <、背景執行 &。
  • 引號與轉義處理 (參考 GNU readline 或自寫狀態機)。
  • 命令歷史、Tab 補全 (Windows 可用 ReadConsole + 歷史緩衝)。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved