Подтвердить что ты не робот

Использование bash (cygwin) внутри программы С#

Мне нужно использовать bash shell "внутри" программы С#. Я хочу подражать пользователю в интерактивном режиме и запускать команды cygwin.

я создал процесс, который запускает bash и перенаправляет stdin, stout и std-ошибку, но я могу: t get tty to work attach - это пример кода, который запускает процесс bash и перенаправляет ввод/вывод.

проблема в том, что у меня нет устройства tty. если я пытаюсь запустить команду tty или команду stty, я получаю сообщение об ошибке

tty - not a tty 
stty - Inappropriate ioctl for device

Я думаю, что это вызвано psi.UseShellExecute = false;

Мне нужно запустить cygwin и отключить эхо с stty -echo, но для этого мне нужно устройство tty. Как я могу создать оболочку cygwin bash с устройством tty и перенаправить stdin, out и ошибку?

1) что пропало?

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading;

namespace shartCygwin
{
    class Program
    {
        private static Queue<string> ResponseQueue = null;
        private static ManualResetEvent ResponseEvent = null;

        static void Main(string[] args)
        {
            ResponseQueue = new Queue<string>();
            ResponseEvent = new ManualResetEvent(false);

            Process bashProcess = new Process();

            bashProcess.StartInfo.FileName = "C:\\cygwin\\bin\\bash.exe"; 
            bashProcess.StartInfo.Arguments = "--login -i ";  
            bashProcess.StartInfo.WorkingDirectory = "C:\\cygwin\\bin";

            bashProcess.StartInfo.EnvironmentVariables["CYGWIN"] = "tty";

            bashProcess.StartInfo.RedirectStandardError = true;
            bashProcess.StartInfo.RedirectStandardInput = true;
            bashProcess.StartInfo.RedirectStandardOutput = true;
            bashProcess.StartInfo.CreateNoWindow = true;
            bashProcess.StartInfo.UseShellExecute = false;
            bashProcess.StartInfo.ErrorDialog = false;

            bashProcess.Start();

            DataReceivedEventHandler errorEventHandler = new DataReceivedEventHandler(ErrorDataReceived);
            DataReceivedEventHandler outEventHandler = new DataReceivedEventHandler(OutDataReceived);
            bashProcess.OutputDataReceived += outEventHandler;
            bashProcess.ErrorDataReceived += errorEventHandler;
            bashProcess.BeginErrorReadLine();
            bashProcess.BeginOutputReadLine();

            while(true)
            {
                Thread.Sleep(1000);
            }
        }

        static void ErrorDataReceived(object sender, DataReceivedEventArgs dataReceivedEventArgs)
        {
            try
            {
                lock (ResponseQueue)
                {
                    Console.WriteLine(dataReceivedEventArgs.Data);
                    ResponseQueue.Enqueue(dataReceivedEventArgs.Data);
                    ResponseEvent.Set();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Data);
            }
        }

        static void OutDataReceived(object sender, DataReceivedEventArgs dataReceivedEventArgs)
        {
            try
            {
                lock (ResponseQueue)
                {
                    Console.WriteLine(dataReceivedEventArgs.Data);
                    ResponseQueue.Enqueue(dataReceivedEventArgs.Data);
                    ResponseEvent.Set();
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.Data);
            }
        }
    }
}
4b9b3361

Ответ 1

Это может или не поможет вам или кому-либо другому, кто сталкивается с этим вопросом. Это ответ на тот же точный вопрос в списке рассылки Cygwin.

> i created a process that runs bash and redirect stdin,stout and std error
> but I can’t get tty to work attached is a sample code that starts bash
> process and redirect the input/output.
> the problem is that i don't have tty device. if i try to run tty command or
> stty command i receive error response 
> tty - not a tty 
> stty - Inappropriate ioctl for device

> i need to run cygwin and disable echo with stty -echo but to do this i need
> a tty device. how can i create a cygwin bash shell with tty device and
> redirect the stdin, out and error ?

  Why exactly do you think you need to run stty and set the tty operating
parameters, when the bash process is quite plainly *not* connected to a tty,
it is connected to your C# application?

  It your application that is in charge of I/O - if it doesn't want echo,
all it has to do is discard the stuff it reads from the process' stdout
instead of displaying it, in your OutDataReceived/ErrorDataReceived handlers.

>             bashProcess.StartInfo.EnvironmentVariables["CYGWIN"] = "tty";

  Don't do this.  Win32 native processes don't understand Cygwin tty
emulation, which is based on pipes.

    cheers,
      DaveK

Источник: http://www.cygwin.com/ml/cygwin/2009-09/msg00637.html

Ответ 2

Замечание, а не реальный ответ, посмотрите на: http://www.codeproject.com/KB/IP/sharpssh.aspx

Чтобы ответить на вопрос:

Ваша неправильная обработка событий... Вам нужно искать e.Data == null в обработчике событий для получения ошибок/результатов. Как только обработчики событий получат это событие И процесс завершился, вы закончили. Таким образом, вы ждете трех ручек, один из которых сообщает вам, что событие Process.Exited уволено, одно, чтобы сообщить вам, что вывод ошибки получен null, один, чтобы сообщить вам, что полученный результат был null. Обязательно также установите:

process.EnableRaisingEvents = true;

Вот полный ответ, перенаправляющий вывод на текущую консоль:

    static int RunProgram(string exe, params string[] args)
    {
        ManualResetEvent mreProcessExit = new ManualResetEvent(false);
        ManualResetEvent mreOutputDone = new ManualResetEvent(false);
        ManualResetEvent mreErrorDone = new ManualResetEvent(false);

        ProcessStartInfo psi = new ProcessStartInfo(exe, String.Join(" ", args));
        psi.WorkingDirectory = Environment.CurrentDirectory;

        psi.RedirectStandardError = true;
        psi.RedirectStandardOutput = true;
        psi.CreateNoWindow = true;
        psi.UseShellExecute = false;
        psi.ErrorDialog = true;

        Process process = new Process();
        process.StartInfo = psi;

        process.Exited += delegate(object o, EventArgs e)
        {
            Console.WriteLine("Exited.");
            mreProcessExit.Set();
        };
        process.OutputDataReceived += delegate(object o, DataReceivedEventArgs e) 
        {
            if( e.Data != null )
                Console.WriteLine("Output: {0}", e.Data); 
            else
                mreOutputDone.Set(); 
        };
        process.ErrorDataReceived += delegate(object o, DataReceivedEventArgs e)
        {
            if (e.Data != null)
                Console.Error.WriteLine("Error: {0}", e.Data);
            else
                mreErrorDone.Set();
        };

        process.EnableRaisingEvents = true;
        Console.WriteLine("Start: {0}", process.StartInfo.FileName); 
        process.Start();
        process.BeginErrorReadLine();
        process.BeginOutputReadLine();

        if (process.HasExited) 
            mreProcessExit.Set();

        while(!WaitHandle.WaitAll(new WaitHandle[] { mreErrorDone, mreOutputDone, mreProcessExit }, 100))
            continue;
        return process.ExitCode;
    }

Ответ 3

Просто выполните что-то вроде:

C:\cygwin\bin\bash -li /cygdrive/c/<path-to-shell-script-location>/chmod-cmd.sh 

И затем защелкните вход и выход.

ИЛИ используйте mintty.