如何在.NET Core控制台应用中实现Shell命令的交互式循环执行?
解决交互式命令执行与循环交互问题
你的现有代码只能处理一次性执行的命令,无法应对ssh这类需要用户输入回应的交互式场景。要实现实时输出命令结果并支持用户输入,需要修改成异步读取输出流、监听用户输入并写入进程标准输入的模式,具体实现如下:
核心修改思路
- 开启
RedirectStandardInput,允许向进程输入内容 - 异步读取
StandardOutput和StandardError,实时输出到控制台 - 单独监听用户输入,将输入内容转发给进程的标准输入
- 保持循环直到进程退出
完整代码示例
using System; using System.Diagnostics; using System.Threading.Tasks; class Program { static async Task Main(string[] args) { await RunInteractiveCommand("ssh", "100.100.109.86"); } static async Task RunInteractiveCommand(string command, string args) { var process = new Process() { StartInfo = new ProcessStartInfo { FileName = command, Arguments = args, RedirectStandardOutput = true, RedirectStandardError = true, RedirectStandardInput = true, // 开启标准输入重定向 UseShellExecute = false, CreateNoWindow = true, // 确保编码匹配,避免乱码 StandardOutputEncoding = System.Text.Encoding.UTF8, StandardErrorEncoding = System.Text.Encoding.UTF8 } }; // 异步读取输出流 var outputTask = Task.Run(async () => { string line; while ((line = await process.StandardOutput.ReadLineAsync()) != null) { Console.WriteLine(line); } }); // 异步读取错误流 var errorTask = Task.Run(async () => { string line; while ((line = await process.StandardError.ReadLineAsync()) != null) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine(line); Console.ResetColor(); } }); // 监听用户输入并写入进程标准输入 var inputTask = Task.Run(async () => { string input; while (!process.HasExited) { if (Console.KeyAvailable) { input = Console.ReadLine(); await process.StandardInput.WriteLineAsync(input); await process.StandardInput.FlushAsync(); } await Task.Delay(100); // 避免过度占用CPU } }); process.Start(); // 等待所有任务完成 await Task.WhenAll(outputTask, errorTask, inputTask); process.WaitForExit(); } }
关键细节说明
- 异步流读取:用
ReadLineAsync()逐行读取输出,避免ReadToEnd()阻塞到进程结束,实现实时输出 - 标准输入转发:开启
RedirectStandardInput后,将用户在控制台的输入写入进程的标准输入,满足交互式命令的输入需求 - 编码设置:指定UTF8编码防止输出乱码,适配多数命令行工具的编码
- CPU占用优化:用户输入监听循环中加入
Task.Delay(100),避免无意义的空循环消耗过多资源
如果需要支持用户执行多个命令(比如执行完一个命令后回到自定义的命令提示符),可以在外层套一个循环,比如:
static async Task Main(string[] args) { while (true) { Console.Write("> "); var userInput = Console.ReadLine(); if (string.IsNullOrWhiteSpace(userInput)) continue; if (userInput.Equals("exit", StringComparison.OrdinalIgnoreCase)) break; // 拆分命令和参数(简单拆分,复杂场景需用命令行解析库) var parts = userInput.Split(' ', StringSplitOptions.RemoveEmptyEntries); if (parts.Length == 0) continue; var command = parts[0]; var argsStr = string.Join(" ", parts[1..]); await RunInteractiveCommand(command, argsStr); } }
这样用户就可以在自定义提示符下输入多个命令,包括交互式命令。
内容的提问来源于stack exchange,提问作者Vinyl Warmth
相关产品推荐
相关产品推荐

