Does not seem specific to our Java 7 backtick logic, but the Java 6 logic does at least provide the execution error as a string:
system ~/projects/jruby-1.7 $ pickjdk 5 ; jruby -e 'puts `blahblah`'
New JDK: jdk1.7.0_45.jdk
system ~/projects/jruby-1.7 $ pickjdk 1 ; jruby -e 'puts `blahblah`'
New JDK: 1.6.0.jdk
/bin/sh: blahblah: command not found
system ~/projects/jruby-1.7 $ ruby-1.9.3 -e 'puts `blahblah`'
-e:1:in ``': No such file or directory - blahblah (Errno::ENOENT)
from -e:1:in `<main>'
With a little more experimentation, it looks like any nonzero exit status returns an empty string, no matter if there was something on stdout or not. In MRI, you get the stdout from the command even if there was a nonzero exit status.
As of 1.7.12, the behavior I've observed is that the exit status is actually completely ignored. And you still get the stdout, but the stderr is completely ignored. This is identical to the MRI behavior (2.1.1), except MRI apparently lets stderr pass right through to my terminal -- the program still doesn't see that error, but at least I can see it this time.
There's still the difference with getting an ENOENT or not. I would guess what's happening here is that Ruby can just call the native C stuff like execvp(), which handles the PATH environment variable without forcing you to actually launch a shell, and that's where the ENOENT comes from. But for more complicated commands, you have to use the shell anyway:
irb(main):007:0> `notfound < /dev/null`
sh: 1: notfound: not found
As far as I can tell, since it's the shell reporting the error, it shows up on stderr, gets passed through to my terminal, and the program just gets an empty string. So I would guess what happens here is JRuby always uses /bin/sh (even for commands we could handle without it), and it always discards stderr, instead of letting it through to the terminal.
I'm learning that if I care about whether a command actually ran, backticks are probably a bad idea. Still, would it be useful to duplicate MRI's behavior here?
On a further note, jruby-1.7.19 still has this behavior, and while in MacOSX/Linux + JDK7/8 a non existant command returns "", the same jruby version on Windows will properly raise an exception:
Errno::ENOENT: No such file or directory - command_that_doesnt_exist
from (irb):2:in `evaluate'
The behaviour in both environments should be consistent (and ideally also between JRuby and MRI).
So this is a bit gnarly. The logic for ` lives in process_manager.rb and is implemented in Ruby using Java integration. It calls into LaunchConfig to check if we should use sh for the backtick, which returns true unconditionally when not running on Windows. That causes it to use sh, which doesn't find the command, but stderr appears not to be hooked up.
Note that MRI is a bit inconsistent here too...if you have a bad command with any shell characters nearby, it will switch to running with sh and NOT raise any error:
 ~/projects/ruby $ rvm ruby-1.9 do ruby -e '`boop $FOO`; puts "ok!"'
sh: boop: command not found
MRI raises an ENOENT exception when using backtics with a nonexistant command. Jruby 1.7.8 on JRE 1.7.0_45 returns an empty string.
The text was updated successfully, but these errors were encountered: