2009-09-14 27 views
20

necesito usar el programa C# dentro del programa "bash shell". Quiero imitar el tipeo del usuario en modo interactivo y ejecutar comandos de cygwin.Usando bash (cygwin) dentro del programa C#

creé un proceso que ejecuta bash y redirigir stdin, stout y std error pero no puedo obtener tty para trabajar adjunto es un código de muestra que inicia el proceso bash y redirige la entrada/salida.

el problema es que no tengo dispositivo tty. Si trato de ejecutar comandos TTY o un comando stty recibo una respuesta de error

tty - not a tty 
stty - Inappropriate ioctl for device 

creo que el presente es causado por psi.UseShellExecute = false;

necesito para ejecutar cygwin y desactivar eco con stty -echo pero para hacer esto i necesita un dispositivo tty. ¿Cómo puedo crear un shell cygwin bash con dispositivo tty y redirigir el stdin, out y error?

1) ¿Qué es lo que falta?

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); 
      } 
     } 
    } 
} 
+0

Ejecuté su programa, y ​​aunque veo el error "Ioctl inapropiado para el dispositivo", también veo el aviso de cygwin bash después de eso. ¿Cuál es exactamente el problema? Quité la línea CYGWIN = tty y veo que la salida de TE es en bruto, con los códigos de control que se muestran. –

+0

@Hemlock - Creo que la clave aquí, basada en la respuesta de Kevin Mark, es que tienes que decidir si usar o no el eco, entonces realmente importa si desactivas el eco/etc ... Y qué motivación hay ¿Por intentar engañar a CYGWIN para que use un TTY? – Peter

Respuesta

2

Una nota al margen, no una respuesta real, echar un vistazo a: http://www.codeproject.com/KB/IP/sharpssh.aspx

Para responder a la pregunta: ¿

Tu no manejar correctamente los eventos ... Usted tiene que mirar para el correo .Data == null en el controlador de eventos para Error/Salida recibida. Una vez que ambos manejadores de eventos reciban este evento Y el proceso haya terminado, ya terminaste. Por lo tanto, espera en tres controles, uno para indicarle el evento Proceso. Se activó el evento, uno para indicarle que la salida de error recibió nulo, uno para indicarle que la salida recibida es nula. Asegúrese de ajustar también:

process.EnableRaisingEvents = true; 

Aquí está la respuesta completa a la reorientación de la producción actual de la consola:

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; 
    } 
+0

el problema es que no tengo dispositivo tty. si intento ejecutar el comando tty o el comando stty recibo una respuesta de error tty - no es un tty stty - ioctl inapropiado para el dispositivo Creo que esto es causado por psi.UseShellExecute = false; necesito correr cygwin y desactivar echo con stty -echo pero para hacer esto necesito un dispositivo tty. ¿Cómo puedo crear un shell cygwin bash con un dispositivo tty y redirigir el stdin, salir y el error? –

+0

Su problema es que st-echo intenta establecer configuraciones en un terminal, pero cuando redirige stdout a otro conducto, este comando realiza un error. El código de redirección de csharptest.net funciona para usted, pero la redirección y la configuración de las cosas relacionadas con la consola se prohiben entre sí. Debe cambiar su skript llamado para detectar el caso en que se redirige la salida, p. simplemente llamando a stty -echo para verificar si se te redirige o no. –

6

Esto puede o no usted o cualquier otra persona que pasa a través de esta pregunta ayudará. Esta es la respuesta dada a la misma pregunta exacta en la lista de correo de 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's 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's tty 
emulation, which is based on pipes. 

    cheers, 
     DaveK

Fuente: http://www.cygwin.com/ml/cygwin/2009-09/msg00637.html

0

Sólo ejecutivo de algo como:

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

Y luego trabar sobre la entrada y salida.

O use mintty.

Cuestiones relacionadas