2009-09-14 2 views
20

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

Я создал процесс, который запускает bash и перенаправляет stdin, stout и std-ошибку, но я могу; t получить tty для работы в приложении - это пример кода, который запускает процесс bash и перенаправляет ввод/вывод.

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

tty - not a tty 
stty - Inappropriate ioctl for device 

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

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

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

Я запустил вашу программу, и хотя я вижу ошибку «Несоответствующий ioctl для устройства», я также вижу подсказку cygwin bash после этого. В чем именно проблема? Я удалил строку CYGWIN = tty, и я вижу, что вывод te сырой, с отображаемыми управляющими кодами. –

+0

@Hemlock - Я думаю, что ключ здесь, основываясь на ответе Кевина Марка, заключается в том, что вы решаете, использовать или не использовать эхо, так что действительно ли имеет значение, если вы отключите эхо/etc ... И какая мотивация есть для попытки обмануть CYGWIN в использовании TTY? – Peter

ответ

2

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

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

Вы не правильно обработки событий ... Вам нужно искать е .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; 
    } 
+0

проблема в том, что у меня нет устройства tty. , если я пытаюсь запустить команду tty или команду stty, я получаю сообщение об ошибке tty - not a tty stty - Несоответствующий ioctl для устройства Я думаю, что это вызвано psi.UseShellExecute = false; Мне нужно запустить cygwin и отключить эхо с stty -echo, но для этого мне нужно устройство tty. Как я могу создать оболочку bash cygwin с устройством tty и перенаправить stdin, out и error? – 2009-09-14 22:09:40

+0

Ваша проблема в том, что stty -echo пытается установить настройки на терминале, но когда вы перенаправляете stdout на другой канал, эта команда делает ошибку. Код перенаправления csharptest.net действительно работает для вас, но перенаправление и настройка связанных с консолью вещей запрещают друг друга. Вы должны изменить свой вызов skript, чтобы определить случай, когда выход перенаправляется, например. просто вызовите stty -echo, чтобы проверить, перенаправлены ли вы или нет. –

6

Это может или не может помочь вам или кому-либо еще, кто происходит по этому вопросу. Это ответ на тот же самый точный вопрос в списке рассылки 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

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

0

Просто запустите что-то вроде:

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

А затем застегнуть на входе и выходе.

ИЛИ использование mintty.

Смежные вопросы