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

C# 呼叫 DOS 命令完整指南:Process 類別最佳實踐

     編輯:關於C語言

核心類別:System.Diagnostics.Process

關鍵屬性設定:

  • UseShellExecute = false:必須關閉 Shell 執行,才能重導向輸入/輸出/錯誤
  • RedirectStandardInput/Output/Error = true:啟用標準流重導向
  • CreateNoWindow = true:隱藏命令視窗
  • WorkingDirectory:設定工作目錄

基本範本:執行單一命令並取得輸出

public static string RunCommand(string command, string workingDir = null, int timeoutMs = 60000) {
    using (Process p = new Process()) {
        p.StartInfo.FileName = "cmd.exe";
        p.StartInfo.Arguments = "/c " + command;  // /c 執行完關閉;/k 保留視窗
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.RedirectStandardInput = true;
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.RedirectStandardError = true;
        p.StartInfo.CreateNoWindow = true;
        if (!string.IsNullOrEmpty(workingDir)) {
            p.StartInfo.WorkingDirectory = workingDir;
        }

        p.Start();
        // 可選:寫入額外命令到標準輸入
        // p.StandardInput.WriteLine("dir");
        // p.StandardInput.WriteLine("exit");

        // 非同步讀取避免死結 (大量輸出時)
        string output = p.StandardOutput.ReadToEnd();
        string error = p.StandardError.ReadToEnd();

        bool exited = p.WaitForExit(timeoutMs);
        if (!exited) {
            p.Kill();
            throw new TimeoutException($"命令執行逾時 ({timeoutMs}ms): {command}");
        }

        if (p.ExitCode != 0 && !string.IsNullOrEmpty(error)) {
            throw new InvalidOperationException($"命令失敗 (ExitCode={p.ExitCode}): {error}");
        }
        return output;
    }
}

進階範例:互動式命令 (如 ftp、telnet、python 互動模式)

public static string RunInteractive(string exePath, string[] commands, string workingDir = null) {
    using (Process p = new Process()) {
        p.StartInfo.FileName = exePath;
        p.StartInfo.UseShellExecute = false;
        p.StartInfo.RedirectStandardInput = true;
        p.StartInfo.RedirectStandardOutput = true;
        p.StartInfo.RedirectStandardError = true;
        p.StartInfo.CreateNoWindow = true;
        if (!string.IsNullOrEmpty(workingDir)) p.StartInfo.WorkingDirectory = workingDir;

        p.Start();

        foreach (string cmd in commands) {
            p.StandardInput.WriteLine(cmd);
        }
        p.StandardInput.WriteLine("exit"); // 重要:結束互動會話

        string output = p.StandardOutput.ReadToEnd();
        string error = p.StandardError.ReadToEnd();
        p.WaitForExit();

        return output;
    }
}

// 使用範例:批次 ping
string result = RunInteractive("cmd.exe", new[] {
    "ping 127.0.0.1",
    "ping www.google.com"
});

常見問題排查表

現象原因解決
StandardOutput 為空程式輸出到 StandardError、或緩衝區未刷新同時讀取 StandardError;若為外部程式,確認其輸出機制
ReadToEnd() 卡死標準輸出緩衝區滿、程式等待輸入使用非同步 BeginOutputReadLine + 事件處理;或分執行緒讀取輸出/錯誤
中文亂碼主控台編碼非 UTF-8 (預設 CP950/CP936)p.StartInfo.StandardOutputEncoding = Encoding.GetEncoding(950); (繁中) 或 Encoding.UTF8 (需外部程式支援)
需要管理員權限命令需提升權限 (如 netsh、diskpart)p.StartInfo.Verb = "runas"; p.StartInfo.UseShellExecute = true; (但無法重導向流)
路徑含空格引號處理錯誤檔名/路徑加雙引號:@""""C:\Program Files\app.exe""""

現代化非同步版本 (.NET Core / .NET 5+ 推薦)


using System.Diagnostics;
using System.Threading.Tasks;

public static async Task<(int ExitCode, string Output, string Error)> RunAsync(
    string fileName, string arguments, string workingDir = null, 
    Dictionary envVars = null, CancellationToken ct = default) {

    var psi = new ProcessStartInfo {
        FileName = fileName,
        Arguments = arguments,
        UseShellExecute = false,
        RedirectStandardOutput = true,
        RedirectStandardError = true,
        CreateNoWindow = true,
        WorkingDirectory = workingDir ?? Environment.CurrentDirectory
    };

    if (envVars != null) {
        foreach (var kv in envVars) psi.EnvironmentVariables[kv.Key] = kv.Value;
    }

    using (var process = new Process { StartInfo = psi, EnableRaisingEvents = true }) {
        var outputBuilder = new StringBuilder();
        var errorBuilder = new StringBuilder();

        process.OutputDataReceived += (s, e) => { if (e.Data != null) outputBuilder.AppendLine(e.Data); };
        process.ErrorDataReceived += (s, e) => { if (e.Data != null) errorBuilder.AppendLine(e.Data); };

        process.Start();
        process.BeginOutputReadLine();
        process.BeginErrorReadLine();

        await process.WaitForExitAsync(ct);
        return (process.ExitCode, outputBuilder.ToString(), errorBuilder.ToString());
    }
}

實務建議

  • 優先使用原生 .NET API:檔案操作用 System.IO、網路用 HttpClient、壓縮用 System.IO.Compression,避免呼叫外部命令。
  • 超時機制:生產環境務必設定 WaitForExit(timeout) 或 CancellationToken。
  • 日誌記錄:記錄命令、參數、工作目錄、ExitCode、輸出/錯誤,便於事後除錯。
  • 安全性:嚴禁直接拼接使用者輸入到命令參數,防止命令注入;使用 ProcessStartInfo.ArgumentList (.NET Core 3.1+) 陣列傳參。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved