鉴于以下代码在 Linux 上的 Mono 中运行,我可以从 C# 成功运行 ssh 并在远程机器上获得 shell 提示符。我可以键入命令并获得输出。但是我不知道如何让我在那个 shell 中输入的内容回显。当我键入 ls
并按回车键时,您看不到 ls
或按回车键后的换行符,您只能看到它的输出。我已经验证 ssh 正在分配一个 tty。目标 shell 是交互模式下的 bash,因此在那里启用了 readline。问题必须在于 C# 如何将 STDIN 和 STDOUT 连接到 Console
。 Google 帮不上忙,所以我希望这里有人能提供帮助。
var process_info = new ProcessStartInfo("/usr/bin/ssh");
process_info.Arguments = "-ttt hostname";
Console.Out.WriteLine("Arguments: [" + process_info.Arguments + "]");
process_info.CreateNoWindow = true;
process_info.UseShellExecute = true;
var process = new Process();
process.StartInfo = process_info;
try {
process.Start();
process.WaitForExit();
exitCode = process.ExitCode;
}
catch (Exception e)
{
exitCode = this.ExitCode == 0 ? 255 : exitCode;
Console.WriteLine(e.ToString());
}
Console.Out.WriteLine("ExitCode: " + exitCode);
最佳答案
也许这就是您想要做的:
using System;
using System.Diagnostics;
using System.IO;
using System.Threading;
namespace Echo
{
class Program
{
private static void Read(StreamReader reader)
{
new Thread(() =>
{
while (true)
{
int current;
while ((current = reader.Read()) >= 0)
Console.Write((char)current);
}
}).Start();
}
static void Main(string[] args)
{
ProcessStartInfo startInfo = new ProcessStartInfo(@"/usr/bin/ssh");
startInfo.Arguments = "-ttty localhost";
startInfo.CreateNoWindow = true;
startInfo.ErrorDialog = false;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardInput = true;
startInfo.RedirectStandardOutput = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
Thread.Sleep(15000); //time to login
Read(process.StandardOutput);
Read(process.StandardError);
process.StandardInput.WriteLine("echoing your input now");
while (!process.HasExited)
try { process.StandardInput.WriteLine(Console.ReadLine()); }
catch {}
Console.WriteLine(process.ExitCode.ToString());
}
}
}
编辑 1
您需要重定向 StandardInput 以回显它,但是 Windows 中的 cmd 将逐行详细说明它(即使您使用 Console.ReadKey() => process.StandardInput.Write),所以您可以'键入时没有 shell 支持(如果您想深入了解,请查看此 question/answer)。 但是带有 linux ssh 的 mono 与 windows cmd 的行为不同,所以以下可能是可以接受的: 命令被回显,甚至在键入目录时选项卡也被管理(请看下面的屏幕截图)!最后请注意 tty 已正确设置。
using System;
using System.Diagnostics;
using System.IO;
using System.Text;
using System.Threading;
namespace Echo
{
class Program
{
private static Process process;
private static void Read(StreamReader reader)
{
new Thread(() =>
{
while (!process.HasExited)
{
int current;
while ((current = reader.Read()) >= 0)
Console.Write((char)current);
}
}).Start();
}
static void Main(string[] args)
{
ProcessStartInfo startInfo = new ProcessStartInfo(@"/usr/bin/ssh");
startInfo.Arguments = "-ttty localhost";
startInfo.CreateNoWindow = true;
startInfo.ErrorDialog = false;
startInfo.RedirectStandardError = true;
startInfo.RedirectStandardInput = true;
startInfo.RedirectStandardOutput = true;
startInfo.UseShellExecute = false;
startInfo.CreateNoWindow = true;
process = new Process();
process.StartInfo = startInfo;
process.Start();
Thread.Sleep(15000); //time to login
Read(process.StandardOutput);
Read(process.StandardError);
process.StandardInput.WriteLine("echo echoing your input now");
//Console.ReadLine();
string theLine = "\n";
while (!process.HasExited)
try {
ConsoleKeyInfo kinfo = Console.ReadKey(true);
char theKey = kinfo.KeyChar;
theLine += theKey;
process.StandardInput.Write(theKey) ;
process.StandardInput.Flush();
if (theKey.Equals('\n'))
{
Console.WriteLine(theLine);
theLine = "\n";
}
}
catch { }
Console.WriteLine(process.ExitCode.ToString());
}
}
}
编辑 2
如果你还想管理 UpArrow/DownArrow 的终端转义序列,这里是代码(在我的 Ubuntu 终端上测试过)
string theLine = "\n";
string theEsc = ((char)27).ToString();
while (!process.HasExited)
try {
//byte[] bytes = new byte[1];
ConsoleKeyInfo kinfo = Console.ReadKey(true);
char theKey = kinfo.KeyChar;
theLine += theKey;
switch (kinfo.Key)
{
case ConsoleKey.DownArrow:
process.StandardInput.Write(theEsc+"[B");
break;
case ConsoleKey.UpArrow:
process.StandardInput.Write(theEsc+"[A");
break;
default:
process.StandardInput.Write(theKey);
break;
}
process.StandardInput.Flush();
if (theKey.Equals('\n'))
{
Console.Write(theLine);
theLine = "\n";
}
}
编辑 3
只是对我的评论进行跟进,建议使用恢复 echo 的命令(引用 here )。 这是对代码的更改:
process.StandardInput.WriteLine("stty -a");
process.StandardInput.WriteLine("stty echo"); // or "reset" insted of "stty echo"
process.StandardInput.WriteLine("echo echoing your input now");
回到你原来的代码(因为你没有重定向标准输入),你可以做类似下面的事情
process_info.Arguments = "-ttt hostname 'stty echo; '$SHELL' -i'"; // or reset insted of stty echo
也看看这个 answer。
结论您显示的来源 - 更具体地说是 c# System.Process - 不应该回显 任何东西(除非有人故意重定向标准 I/O,正如我在第一个示例和编辑 1 和 2 中所做的那样)。 Echoing 是 shell 的一种行为,在 Linux 和 Windows 中:可以按照编辑 3 中所示进行管理。
关于c# - 交互式 c# System.Process 不回显输入,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29240750/