c# - 交互式 c# System.Process 不回显输入

标签 c# linux shell ssh mono

鉴于以下代码在 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());
        }
    }
}

first example of using tab while typing a dir check tty example of echoing the ssh commmands

编辑 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/

相关文章:

android - Android 上 USB 设备的 Linux 文件权限

linux - QEMU 中的滚动选项

新 Lamp linux 服务器上的 Php session

bash - 如何查看哪些用户正在执行命令(Shell 脚本)

c# - 将 midi 信号从 c# 发送到 ableton

c# - 使链接从 window.open 弹出窗口中消失

c# - C# 中的 SQLGeography

c# - int数组转字符串

linux - bash 脚本查找排列总数

bash - bash shell 脚本中大于 255 的数字