2

test.rb に次のコードがあります。

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.exeは、私が作成したコンソール アプリケーションで、 にありC:\Program Files\foo\ます。私が実行するとbar.exe

  • それは出力します"Hello world!"
  • のような任意の引数を指定するとbar.exe /blah、ヘルプ メッセージが出力されます。

実行する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>'

コードを call に変更するとpopen3:

Open3.popen3(cmd, '')

エラーは表示されずErrno::ENOENT、代わりにヘルプ メッセージが表示されますが、"Hello World"出力が必要です。

解決策を探しましたが、「実行可能ファイルが見つからないときに Open3.popen3 が間違ったエラーを返すのはなぜですか?」への回答を含め、何も機能していません。

このエラーが発生する理由と解決方法を教えてください。

4

3 に答える 3

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を使用して入力されたため認識されません。\ f\ b

これを処理するには、2 番目の例のようにバックスラッシュをエスケープする方法と、3 番目の例のように単一引用符で囲まれた文字列を使用する方法の 2 つがあります。2 番目の手段を使用するのは面倒だと考えられているため、読みやすく、保守を容易にするために、後者を使用してください。視覚的なノイズが少ない同じ文字が得られます。これは、ほとんどの言語での文字列の使用に当てはまります。

2 番目に知っておくべきことは、Ruby はパス区切り文字として逆スラッシュを必要としないということです。IOのドキュメントには次のように書かれています:

Ruby は、可能であれば、異なるオペレーティング システムの規則間でパス名を変換します。たとえば、Windows システムでは、ファイル名"/gumby/ruby/test.rb""\gumby\ruby\test.rb". Ruby 文字列で Windows スタイルのファイル名を指定するときは、必ずバックスラッシュをエスケープしてください。

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

ここでの例では、Unix スタイルのスラッシュを使用します。File::ALT_SEPARATOR を使用して、プラットフォーム固有の区切り文字を取得できます。

最後に、STDLib の Ruby のシェルとシェルワードを見てください。彼らはあなたの友達です。

于 2016-08-18T19:20:11.893 に答える
0

「Program Files」がスペースを含むフォルダーであるため、問題が発生しています。その場合は常に、cmd.exe プロンプトの場合と同様に、二重引用符で囲む必要があります。また、二重引用符を使用する場合は、バックスラッシュ文字 "\" がエスケープ文字であることを覚えておく必要があります。そのため、Windows で適切なフォルダー セパレータを取得するには、バックスラッシュを 2 つ使用する必要があります。私の環境で実際に何かを返すコードを使用します。あなたの好みに合わせて調整してください。したがって、コードは次のようになります。

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

git に渡すコマンド ライン パラメーターがある場合は、次のようにします。

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
于 2016-08-18T18:24:37.810 に答える
0

(および のような関連するメソッド)Open3.popen3([bin, bin])への単一の引数に対するシェル コマンド処理を防止するために使用します。popen3spawn

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

于 2017-01-27T20:41:44.430 に答える