Я пытаюсь написать камень, который взаимодействует с командой Android ADB. У меня проблемы с попыткой понять, как аргументы передаются подпроцессам.
Я использую гем POpen4, который является просто оберткой вокруг платформных модулей open3 / open4. В OSX я запускаю следующее и получаю желаемый результат:
>> require 'POpen4'
=> true
>> POpen4::popen4("/Library/android-sdk-mac_x86/platform-tools/adb shell pm list packages -f") do |pout, perr, pin|
?> pout.each { |line| puts line.to_s.strip }
>> end
package:/system/app/Fallback.apk=com.android.fallback
package:/system/app/SoundRecorder.apk=com.android.soundrecorder
..<snip>..
package:/system/app/VpnServices.apk=com.android.server.vpn
=> #<Process::Status: pid=13833,exited(0)>
Когда я запускаю то же самое на Win32, я получаю:
irb(main):001:0> require 'POpen4'
=> true
irb(main):002:0> POpen4::popen4("C:\\Android\\android-sdk-windows\\platform-tools\\adb.exe shell pm list packages -f")
Errno::ENOENT: No such file or directory - C:\Android\android-sdk-windows\platform-tools\adb.exe shell pm list packages -f
from C:/Ruby192/lib/ruby/1.9.1/open3.rb:202:in `spawn'
from C:/Ruby192/lib/ruby/1.9.1/open3.rb:202:in `popen_run'
from C:/Ruby192/lib/ruby/1.9.1/open3.rb:90:in `popen3'
from C:/Ruby192/lib/ruby/gems/1.9.1/gems/win32-open3-19-0.0.1/lib/win32/open3.rb:5:in `popen4'
from C:/Ruby192/lib/ruby/gems/1.9.1/gems/POpen4-0.1.4/lib/popen4.rb:48:in `popen4'
from (irb):2
from C:/Ruby192/bin/irb:12:in `<main>'
Если я наблюдаю за тем, что делает Ruby, используя procxp, я вижу, что он обрабатывает весь аргумент popen4
как команду для запуска:
ruby.exe 5800 QueryDirectory C:\Android\android-sdk-windows\platform-tools\adb.exe shell pm list packages -f.exe NO SUCH FILE
ruby.exe 5800 QueryOpen C:\Android\android-sdk-windows\platform-tools\adb.exe shell pm list packages -f.exe FAST IO DISALLOWED
ruby.exe 5800 CreateFile C:\Android\android-sdk-windows\platform-tools\adb.exe shell pm list packages -f.exe NAME NOT FOUND
ruby.exe 5800 QueryDirectory C:\Android\android-sdk-windows\platform-tools\adb.exe shell pm list packages -f.com NO SUCH FILE
ruby.exe 5800 QueryOpen C:\Android\android-sdk-windows\platform-tools\adb.exe shell pm list packages -f.com FAST IO DISALLOWED
ruby.exe 5800 CreateFile C:\Android\android-sdk-windows\platform-tools\adb.exe shell pm list packages -f.com NAME NOT FOUND
ruby.exe 5800 QueryDirectory C:\Android\android-sdk-windows\platform-tools\adb.exe shell pm list packages -f.cmd NO SUCH FILE
ruby.exe 5800 QueryOpen C:\Android\android-sdk-windows\platform-tools\adb.exe shell pm list packages -f.cmd FAST IO DISALLOWED
ruby.exe 5800 CreateFile C:\Android\android-sdk-windows\platform-tools\adb.exe shell pm list packages -f.cmd NAME NOT FOUND
ruby.exe 5800 QueryDirectory C:\Android\android-sdk-windows\platform-tools\adb.exe shell pm list packages -f.bat NO SUCH FILE
ruby.exe 5800 QueryOpen C:\Android\android-sdk-windows\platform-tools\adb.exe shell pm list packages -f.bat FAST IO DISALLOWED
ruby.exe 5800 CreateFile C:\Android\android-sdk-windows\platform-tools\adb.exe shell pm list packages -f.bat NAME NOT FOUND
ruby.exe 5800 CreateFile C:\Android\android-sdk-windows\platform-tools\adb.exe shell pm list packages -f NAME NOT FOUND
ruby.exe 5800 CreateFile C:\Android\android-sdk-windows\platform-tools\adb.exe shell pm list packages -f NAME NOT FOUND
Хотя в документах popen3
сказано, что это следует рассматривать как командную строку и аргументы:
The parameters +cmd…+ is passed to Process.spawn. So a commandline string and list of argument strings can be accepted as follows.
Open3.popen3("echo a") {|i, o, e, t| ... }
Open3.popen3("echo", "a") {|i, o, e, t| ... }
Open3.popen3(["echo", "argv0"], "a") {|i, o, e, t| ... }
Что мне здесь не хватает?