用 C#/PowerShell 呼叫 .exe 程式,透過 StandardOuput、StandardError 讀取程式輸出算是 .NET 基本技巧 (參考:命令列工具的 stdout, stderr 輸出與 .NET 整合應用),理論上要整合各式 CLI 程式都不成問題。今天踢到一塊鐵板,才知自己見識淺薄。

我想用 PowerShell 呼叫 gpg --full-gen-key 簡化金鑰產生作業,有段程式寫法如下:

$p = New-Object System.Diagnostics.Process
$p.StartInfo.FileName = "gpg.exe"
$p.StartInfo.Arguments = "--full-gen-key"
$p.StartInfo.UseShellExecute = $false
$p.StartInfo.RedirectStandardOutput = $true
$p.StartInfo.RedirectStandardInput = $true
$p.StartInfo.RedirectStandardError = $true
$p.Start() | Out-Null
$p.WaitForExit()

既已設定 RedirectStandardOutput、RedirectStandardError,理論上不管正常或錯誤輸出應都被導向至 StreamReader 等我讀取,殊不知 gpg 還是能列出金鑰型別選項,登楞!

用 CMD 導向指令 gpg --full-gen-key >msg.txt 2>&1 也能印證這點:

爬文查到有人問過類似問題,由網友回覆學到新東西,除了 stdout, stderr 外,還有一個終端機傳輸通道 - /dev/tty (相當於 Windows 世界 CON:),這塊不支援導向處理。

寫一小段 C 來驗證:(參考:Windows VSCode C/C++ 開發環境安裝指令懶人包)

#include <stdio.h>
#include <stdlib.h>

int main() {
    printf("This is a message to stdout\n");
    fprintf(stderr, "This is a message to stderr\n");

    // FILE* fout = fopen("/dev/tty", "w"); for Linux
    FILE* fout = fopen("con:", "w");
    fprintf(fout, "This is a message to /dev/tty\n");
    fclose(fout);    

    return EXIT_SUCCESS;
}

在 Linux 端驗證,結果相同:

爬文跟問 ChatGPT 的結論是 /dev/tty 無法被導向,可能要搞個終端機模擬環境去攔截,工程大了點,決定繞道。

This ariticle introduce the concept of /dev/tty and why it cannot be redirected.


Comments

# by Ben

原來如此,幾個禮拜前用c# redirect git的 ouput和error也遇到這樣的問題

Post a comment