2016-08-18 14 views
2

上ENOENT私はtest.rbに次のコードを持っている:Open3.popen3は間違ったエラーエラー番号を返す:: Windowsの

require 'open3' 
cmd = 'C:\Program Files\foo\bar.exe' 
Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr| 
    puts "stdout: #{stdout.read}" 
    puts "\n\n" 
    puts "stderr: #{stderr.read}" 
end 

bar.exeC:\Program Files\foo\に位置して、私が作成したコンソールアプリケーションです。私はbar.exeを実行すると:それはbar.exe /blahのように、任意の引数を指定して"Hello world!"

  • を出力

    • 、それはヘルプメッセージを出力します。

    私はruby test.rbを実行すると、私はこのエラーを取得:

    C:\RailsInstaller/Ruby2.2.0/lib/ruby/2.2.0/open3.rb:193:in 'spawn': No such file or directory - C:\Program Files\foo\bar.exe (Errno::ENOENT) 
    from C:\RailsInstaller/Ruby2.2.0/lib/ruby/2.2.0/open3.rb:193:in 'popen_run' 
    from C:\RailsInstaller/Ruby2.2.0/lib/ruby/2.2.0/open3.rb:193:in 'popen3' 
    from test.rb:3:in '<main>' 
    

    私はpopen3を呼び出すようにコードを変更した場合:

    Open3.popen3(cmd, '') 
    

    私は私が得る代わりに、Errno::ENOENTエラーを得ることはありませんヘルプメッセージが表示されますが、出力は"Hello World"です。

    私は解決策を探しましたが、 "Why does Open3.popen3 return wrong error when executable is missing?"への回答を含め、何も動作していません。

    なぜこのエラーが発生しますか?どのように解決しますか?

  • +0

    「C:/ Program Files/foo/bar.exe」は代わりに動作しますか? – tadman

    答えて

    0

    「プログラムファイル」がスペースの入ったフォルダであるため、問題が発生しています。それが起こるときはいつでも、あなたはcmd.exeプロンプトと同じように二重引用符を付ける必要があります。二重引用符を使用する場合は、円記号 "\"がエスケープ文字であることを覚えておく必要があります。したがって、Windowsの適切なフォルダ区切り文字を得るために二重バックスラッシュを使用する必要があります。自分の環境で実際に何かを返すコードを使用します。あなたの好みに合わせて調整してください。あなたはgitのに渡すコマンドラインパラメータを使用している場合、あなたはこのようにそれを行うだろう

    require 'open3' 
    cmd = "\"C:\\Program Files\\Git\\bin\\git.exe\"" 
    Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr| 
        puts "stdout: #{stdout.read}" 
        puts "\n\n" 
        puts "stderr: #{stderr.read}" 
    end 
    

    :だからあなたのコードは次のようになります

    require 'open3' 
    cmd = "\"C:\\Program Files\\Git\\bin\\git.exe\" --version" 
    Open3.popen3(cmd) do |stdin, stdout, stderr, wait_thr| 
        puts "stdout: #{stdout.read}" 
        puts "\n\n" 
        puts "stderr: #{stderr.read}" 
    end 
    
    +0

    チャームのように働いた。そんなにありがとう! –

    +1

    パスに二重引用符で囲まれた文字列にエスケープエスケープを使用しないでください。代わりに単純なことをして、Rubyにパスを見つけさせてください。 Rubyは自動的にWindows上のスラッシュを正しく処理し、正しく変換します。詳細は、[IO documentation](http://ruby-doc.org/core-2.3.1/IO.html)のオープニングセクションを参照してください。 –

    +0

    私はBNRで約25年前に "The Tin Man"と呼ばれる仲間と仕事をしていました。それはあなたですか、あなたはジョンですか? –

    1

    瞑想この上:

    cmd = "\P\f\b" 
    cmd.size    # => 3 
    cmd.chars   # => ["P", "\f", "\b"] 
    cmd.chars.map(&:ord) # => [80, 12, 8] 
    
    cmd = "\\P\\f\\b" 
    cmd.size    # => 6 
    cmd.chars   # => ["\\", "P", "\\", "f", "\\", "b"] 
    cmd.chars.map(&:ord) # => [92, 80, 92, 102, 92, 98] 
    
    cmd = '\P\f\b' 
    cmd.size    # => 6 
    cmd.chars   # => ["\\", "P", "\\", "f", "\\", "b"] 
    cmd.chars.map(&:ord) # => [92, 80, 92, 102, 92, 98] 
    

    最初の例のように、パス/ディレクトリ区切り文字として単一のバックスラッシュを含む二重引用符で囲まれた文字列を使用しています。単一のバックスラッシュ\f\bは、二重引用符で囲まれた文字列内の文字をエスケープしている、と彼らは B \またはF \ を使用して型付けされたと認識されていません。

    2番目の例のようにバックスラッシュをエスケープする方法と、3番目の例のようにシングルクォートの文字列を使用する方法の2通りがあります。 2番目の手段を使うのは面倒だと考えられているので、読みやすさとメンテナンスを簡単にするために最後の手段を使用してください。あなたは視覚的ノイズが少ない同じ文字を取得します。これは、ほとんどのランゲージの文字列の使用に適用されます。

    Rubyではパス区切り文字として逆スラッシュを使用する必要はありません。IO documentationは言う:

    Ruby will convert pathnames between different operating system conventions if possible. For instance, on a Windows system the filename "/gumby/ruby/test.rb" will be opened as "\gumby\ruby\test.rb" . When specifying a Windows-style filename in a Ruby string, remember to escape the backslashes:

    "c:\\gumby\\ruby\\test.rb"

    Our examples here will use the Unix-style forward slashes; File::ALT_SEPARATOR can be used to get the platform-specific separator character.

    最後に、あなたはRubyのShellShellwords STDLIBで見なければなりません。彼らはあなたの友人です。

    +0

    詳細な回答をいただきありがとうございます。最初に一重引用符を使用しました。しかし、それは動作しませんでした。奇妙な行動! Jay Godseの提案に続き、うまくいった。 –

    +0

    スペースをエスケープするアドバイスが有効です。エスケープされたバックスラッシュを使用するようアドバイスするだけでノイズが発生します。 –

    +0

    私は完全に同意します。奇妙なことに 'Open3.popen3( 'C:\ Program Files \ foo \ bar.exe')は' Open3.popen3( "\" C:\\ Program Files \\ foo \\ bar.exe \ "") 'うまく動作します。 –

    0

    Open3.popen3([bin, bin])を使用して、popen3(および関連する方法、spawnなど)への単一の引数に対するシェルコマンド処理を防止します。

    お気づきのように、複数の引数はシェルを呼び出さずに正常に渡すことができます(例: Open3.popen3(bin, arg1, arg2))。

    関連する問題