[C#] Processを使用してPythonの対話モードを起動し、内容を出力したい。
解決したいこと
C#でProcessを使い、標準出力、標準エラーを出力したい。
何が起きてる(簡単に)
C#で作った自作のシェルでPython3を対話モードで実行した際、入力待ち表示>>>
(標準エラー)がリアルタイムで出力されず、quit()
またはCtrl+D
で対話モードを終了した後に一気に流れてくる。前提
C#を使ってZshやbashのようなシェルソフトを作ってみたいと考えています。
現在は、C#のProcessを使用して外部ソフトを起動し、ソフトからの標準出力、標準エラーをConsole.WriteLine()を使用し、表示することに取り組んでいます。
質問者はOSや、CPU、低レイヤ、標準入力、標準出力、標準エラー、Unix等、聞いたことがある程度しか知らない、そして、bashやZshのソースコードを読んだことがない。実行環境
パソコン: MacBookPro 2017年モデル
プログラム言語: C#、Python3.9.2
フレームワーク: .NET5
エディタ: JetBrains Rider(EAP)
ターミナル: ターミナル.app(macos標準)、Zsh
発生している問題・エラー
C#
で作った自作のシェルでPython3
を対話モードで実行した際、入力待ち表示>>>
(標準エラー)がリアルタイムで出力されず、quit()
またはCtrl+D
で対話モードを終了した後に一気に流れてくる。
対話モードに対し、自分で入力したもの、実行結果はリアルタイムで表示される。
最後に詰まったように出て来る>>>
の数は、対話モードで何かを入力した回数と一致している。
s|
: C#のProcessのOutputDataReceived
で取得されたものe|
: C#のProcessのErrorDataReceived
で取得されたもの
※自作シェルでの出力の最後に表示されているexitedはC#のProcessのExitedが実行された時に意図的に出力しているものです。
該当するソースコード
public string ExecCommand(string userInput)
{
var processInfo = new ProcessStartInfo(userInput, "");
processInfo.RedirectStandardError = true;
processInfo.RedirectStandardOutput = true;
processInfo.CreateNoWindow = true;
processInfo.UseShellExecute = false;
using var proc = new Process();
proc.EnableRaisingEvents = true;
proc.StartInfo = processInfo;
proc.OutputDataReceived += (sender, ev) =>
{
if (!String.IsNullOrEmpty(ev.Data))
Console.WriteLine($"s| {ev.Data}");
};
proc.ErrorDataReceived += (sender, ev) =>
{
if (!String.IsNullOrEmpty(ev.Data))
Console.WriteLine($"e| {ev.Data}");
};
proc.Exited += (sender, ev) =>
{
Console.WriteLine("exited");
// プロセスが終了すると呼ばれる
};
// プロセスの開始
proc.Start();
// 非同期出力読出し開始
proc.BeginOutputReadLine();
proc.BeginErrorReadLine();
// 終了まで待つ
// ctoken.Token.WaitHandle.WaitOne();
proc.WaitForExit();
return "";
}
実際にはuserInput
に"python3"が入力されており、自作シェルの機能で、/usr/bin/から該当のコマンドに対応する実行ファイルを呼び出す作業を行なっています。
なお、このソースは以下の記事を参考にさせていただきました。
※上に表示されているものは該当部分だけを抜き出しています。全体はこちらをご覧ください。
自分で試したこと
- Processについて調べ、ReadToEnd等でls等のシンプルなコマンドの結果を表示できるようにした。
- 参考にさせていただいたサイトに記載されていたものをそのまま書き写した。
- 期待したものができなかったので、参考にさせていただいたサイトが使っていた
CancellationTokenSource
を使わないように書き換えた。
時間がございましたら、ご指摘いただけると嬉しいです。
長々と失礼いたしました。