2009-09-14 33 views
20

私はbashシェルの "inside" C#プログラムを使う必要があります。インタラクティブモードでのユーザの入力を模倣し、cygwinコマンドを実行したい。C#プログラムの中でbash(cygwin)を使う

私はstdin、stout、およびstdエラーを実行するプロセスを作成しましたが、ttyを動作させるには、bashプロセスを開始し、入出力をリダイレクトするサンプルコードが必要です。

問題は私にttyデバイスがないことです。私がttyコマンドまたはにsttyコマンドを実行しようと私はcygwinの実行とエコーとのstty -echoを無効にしますが、この私を行うにする必要があり、これはpsi.UseShellExecute = false;

から発生していると思うエラー応答に

tty - not a tty 
stty - Inappropriate ioctl for device 

を受け取りますttyデバイスが必要です。どのように私はttyデバイスとcygwinのbashシェルを作成し、stdinをリダイレクトすると、エラーとエラー?

1)何が欠けていますか?

あなたが正しく...あなたは電子を探すために必要なイベントを処理していない:質問に答えるためにhttp://www.codeproject.com/KB/IP/sharpssh.aspx

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 for device」エラーが表示されても、そのあとでcygwin bashプロンプトが表示されます。何が問題なのですか?私はCYGWIN = tty行を削除して、制御コードが表示された状態でte出力がrawであることを確認しました。 –

+0

@Hemlock - Kevin Markの答えに基づく鍵は、エコーを使うかどうかを決めることだと思うので、エコーをオフにすれば本当に問題になります。 CYGWINをTTYを使用するように騙そうとしていますか? – Peter

答えて

2

サイドノートではなく、本当の答えは、見ています.Data ==受信したError/Outputのイベントハンドラではnullです。両方のイベントハンドラがこのイベントを受信し、プロセスが終了すると、完了します。したがって、あなたは3つのハンドルを待っています.1つはProcess.Exitedイベントが発生したこと、1つはエラー出力がnullを受け取ったこと、1つは出力が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 - ttyでない stty - デバイスの不適切なioctl これはpsiに起因すると思います。UseShellExecute = false; 私はcygwinを実行し、stty -echoでechoを無効にする必要がありますが、これを行うにはttyデバイスが必要です。 どのようにttyデバイスでcygwinのbashシェルを作成し、stdin、out、errorをリダイレクトするのですか? –

+0

あなたの問題は、stty -echoが端末の設定をしようとしますが、stdoutを別のパイプにリダイレクトすると、このコマンドはエラーを出します。 csharptest.netによるリダイレクションコードはあなたのために機能しますが、リダイレクトとコンソール関連の設定はお互いを禁止します。出力がリダイレクトされた場合を検出するために、呼び出されたスクリプトを変更する必要があります。あなたがリダイレクトされているかどうかを確認するために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を使用してください。

関連する問題