C# Process.StandardOutput.ReadLine() 挂起
C# Process.StandardOutput.ReadLine() hangs
所以基本上 ReadLine() 方法就挂在最后一行。
我不需要结束进程。主要目标是使用 stdin 和 stdout(in variables/Printed out)执行“cmd-shell”。
如果用异步方法也能达到同样的效果,请在评论中留下。
提前致谢。
{
Process p = new Process()
{
StartInfo = new ProcessStartInfo("cmd")
{
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
CreateNoWindow = true,
Arguments = "/K",
}
};
p.ErrorDataReceived += (s, e) =>
{
if (!string.IsNullOrEmpty(e.Data))
{
Console.WriteLine(e.Data);
}
};
p.Start();
while (true)
{
Console.Write("/SHELL/ #> ");
input = Console.ReadLine();
p.StandardInput.WriteLine(input);
p.BeginErrorReadLine();
Console.WriteLine("Errorgoing...");
while (p.StandardOutput.Peek() > -1) {
Console.WriteLine(p.StandardOutput.Peek());
Console.WriteLine(p.StandardOutput.ReadLine());
// When it hangs, Peek() outputs 67, that represents "C" char.
// Seems like just the last stdout line dont want to be printed out.
}
}
}
}```
在实施了一些技巧之后,我得到了以下代码。相当棘手。
static async Task Main(string[] args)
{
using (SemaphoreSlim semaphore = new SemaphoreSlim(0, 1))
{
Process p = new Process()
{
StartInfo = new ProcessStartInfo("cmd")
{
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
CreateNoWindow = true,
Arguments = "/K set PROMPT=PROMPT$P$G$_",
}
};
p.ErrorDataReceived += (s, e) =>
{
if (e.Data?.Length > 0)
{
Console.WriteLine(e.Data);
}
};
bool wasprompt = false;
string prompt = "";
p.OutputDataReceived += (s, e) =>
{
if (e.Data?.Length > 0)
{
if (e.Data.StartsWith("PROMPT") && e.Data.EndsWith(">"))
{
prompt = e.Data.Substring(6, e.Data.Length - 7);
semaphore.Release();
wasprompt = true;
}
else
{
if (!wasprompt)
Console.WriteLine(e.Data);
else
wasprompt = false;
}
}
};
p.Start();
p.BeginErrorReadLine();
p.BeginOutputReadLine();
await semaphore.WaitAsync();
while (!p.HasExited)
{
Console.Write($"/SHELL/ {prompt}#> ");
string input = Console.ReadLine();
p.StandardInput.WriteLine(input);
if (input == "exit") break;
await semaphore.WaitAsync();
}
p.WaitForExit();
}
Console.WriteLine("Bye.");
Console.ReadKey();
}
经过几次测试,看起来像您期望的那样工作。
想法是将 $_
添加到 PROMPT
环境变量以强制打印提示以输出。然后我抓住那个提示并实现 input/output 与 SemaphoreSlim
同步。
所以基本上 ReadLine() 方法就挂在最后一行。
我不需要结束进程。主要目标是使用 stdin 和 stdout(in variables/Printed out)执行“cmd-shell”。
如果用异步方法也能达到同样的效果,请在评论中留下。 提前致谢。
{
Process p = new Process()
{
StartInfo = new ProcessStartInfo("cmd")
{
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
CreateNoWindow = true,
Arguments = "/K",
}
};
p.ErrorDataReceived += (s, e) =>
{
if (!string.IsNullOrEmpty(e.Data))
{
Console.WriteLine(e.Data);
}
};
p.Start();
while (true)
{
Console.Write("/SHELL/ #> ");
input = Console.ReadLine();
p.StandardInput.WriteLine(input);
p.BeginErrorReadLine();
Console.WriteLine("Errorgoing...");
while (p.StandardOutput.Peek() > -1) {
Console.WriteLine(p.StandardOutput.Peek());
Console.WriteLine(p.StandardOutput.ReadLine());
// When it hangs, Peek() outputs 67, that represents "C" char.
// Seems like just the last stdout line dont want to be printed out.
}
}
}
}```
在实施了一些技巧之后,我得到了以下代码。相当棘手。
static async Task Main(string[] args)
{
using (SemaphoreSlim semaphore = new SemaphoreSlim(0, 1))
{
Process p = new Process()
{
StartInfo = new ProcessStartInfo("cmd")
{
UseShellExecute = false,
RedirectStandardInput = true,
RedirectStandardError = true,
RedirectStandardOutput = true,
CreateNoWindow = true,
Arguments = "/K set PROMPT=PROMPT$P$G$_",
}
};
p.ErrorDataReceived += (s, e) =>
{
if (e.Data?.Length > 0)
{
Console.WriteLine(e.Data);
}
};
bool wasprompt = false;
string prompt = "";
p.OutputDataReceived += (s, e) =>
{
if (e.Data?.Length > 0)
{
if (e.Data.StartsWith("PROMPT") && e.Data.EndsWith(">"))
{
prompt = e.Data.Substring(6, e.Data.Length - 7);
semaphore.Release();
wasprompt = true;
}
else
{
if (!wasprompt)
Console.WriteLine(e.Data);
else
wasprompt = false;
}
}
};
p.Start();
p.BeginErrorReadLine();
p.BeginOutputReadLine();
await semaphore.WaitAsync();
while (!p.HasExited)
{
Console.Write($"/SHELL/ {prompt}#> ");
string input = Console.ReadLine();
p.StandardInput.WriteLine(input);
if (input == "exit") break;
await semaphore.WaitAsync();
}
p.WaitForExit();
}
Console.WriteLine("Bye.");
Console.ReadKey();
}
经过几次测试,看起来像您期望的那样工作。
想法是将 $_
添加到 PROMPT
环境变量以强制打印提示以输出。然后我抓住那个提示并实现 input/output 与 SemaphoreSlim
同步。