Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Backticks don't give exception for nonexistant command #1396

Closed
shawnjgoff opened this issue Jan 10, 2014 · 7 comments
Closed

Backticks don't give exception for nonexistant command #1396

shawnjgoff opened this issue Jan 10, 2014 · 7 comments
Milestone

Comments

@shawnjgoff
Copy link

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.

@headius
Copy link
Member

headius commented Jan 10, 2014

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>'

@shawnjgoff
Copy link
Author

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.

@masover
Copy link

masover commented May 1, 2014

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?

@jsvd
Copy link
Contributor

jsvd commented May 7, 2015

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:

irb(main):002:0> `command_that_doesnt_exist`
Errno::ENOENT: No such file or directory - command_that_doesnt_exist
        from file:/C:/logstash-1.5.0-rc3/vendor/jruby/lib/jruby.jar!/jruby/kerne
l/jruby/process_manager.rb:24:in ``'
        from file:/C:/logstash-1.5.0-rc3/vendor/jruby/lib/jruby.jar!/jruby/kerne
l/jruby/process_manager.rb:49:in ``'
        from (irb):2:in `evaluate'

The behaviour in both environments should be consistent (and ideally also between JRuby and MRI).

@headius
Copy link
Member

headius commented May 7, 2015

Works correctly in JRuby 9k but still broken on jruby-1_7 branch as of today.

@headius
Copy link
Member

headius commented May 7, 2015

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
ok!

@headius
Copy link
Member

headius commented May 8, 2015

This should be fixed now. I duplicated logic from popen that does similar bin checking.

@headius headius closed this as completed May 8, 2015
@headius headius added this to the JRuby 1.7.21 milestone May 8, 2015
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants