3

Using a ruby file (or any rake facility) I need to find out if the user who executes my script is able to execute certain shell commands. In particular g++ etc. Hopefully system independent so if there is some g++.bat, g++.exe or just g++ (etc) it should say yes nevertheless, as long as its on the path and executable on the users system.

Example: if the user has a no-extention executable version of the file and a .cmd version of the file it should say "yes" for the no extension version on a linux system and "yes" to the .cmd version on a windows system. Since the users shell can only execute that version of the file.

The purpose of this is to allow the script to be self-configuring (as much as possible).

Any suggestions on how I might go about doing this?

srcspider
  • 10,977
  • 5
  • 40
  • 35

3 Answers3

5

A quick and dirty way is to simply attempt to execute g++ via the system command and check the return code, for example:

def gpp_exists
  return system("g++ --version")
end

You'd have to do some trickery to avoid getting unwanted output on the console (e.g. redirecting stdout/stderr based on correct OS syntax), but it couldn't be too bad.

maerics
  • 151,642
  • 46
  • 269
  • 291
  • Mm, I considered that, but was put off by `system "g++"` returning false. Didn't consider `--version`, which is a good idea, and, while more specific, better imo than my approach. – Xiong Chiamiov Jun 03 '10 at 22:09
  • 1
    +1. Usually, the best way to check whether or not you can run some executable is to just run the damn executable. After all, even *if* you check that it exists *and* that it is executable *and* that it is in the path, there are still a ton of reasons why it wouldn't work: permissions, resource restrictions, wrong library versions, a corrupted executable due to a filesystem error, not enough memory ... – Jörg W Mittag Jun 03 '10 at 22:22
  • In Rake there is a command sh which works pretty much like system above. That's what I've experimented with, as it can pass to the block the result to and status, but my two problems with it are that first of all you're assuming --version there, and should I not pass anything I would be assuming it exits; and second I can't seem to think of a (universal) way of preventing output to the shell used to execute the script. – srcspider Jun 04 '10 at 04:00
  • @srcspider, redirecting output from the shell can be done as follows in UNIX `g++ --version > /dev/null 2>&1` and like so in Windows `g++ --version 1> NUL 2>&1`; so you just need to detect the OS family then append the appropriate redirection strings. – maerics Jun 04 '10 at 18:14
  • I think I can "finesse" a solution to my problem with that and might just work pretty well for what I'm trying to do. With regard to detecting OS family I can do that easily though the instantiated application object: Rake.application.windows? and Rake.application.unix? Possible simply assume unix syntax will work should it not be windows as the implementation is a little funcky (http://rake.rubyforge.org/classes/Rake/Application.html#M000093). I'm going to tag your question as the answer, but your comment is really the true answer. – srcspider Jun 05 '10 at 02:07
4

Well, File contains both exists? and executable?. ENV['PATH'] gets the directories executables are in (at least on *nix - can someone confirm for Windows?). Combine the two with a bit of magic and you should have a solution.

Edit:

irb(main):001:0> ENV['PATH'].split(':').collect {|d| Dir.entries d if Dir.exists? d}.flatten.include? 'adduser'
=> true
irb(main):002:0> ENV['PATH'].split(':').collect {|d| Dir.entries d if Dir.exists? d}.flatten.include? 'foo'
=> false
Xiong Chiamiov
  • 13,076
  • 9
  • 63
  • 101
  • Only in 1.9 (but that is not a problem). The problem is scanning the path does not really tell the difference between scripts. For example, I can execute "g++ --version" but giving g++ as input will yield false. Now I could test for a partial match, but that can cause problems on its own, I don't feel its worth the quirks. – srcspider Jun 04 '10 at 03:56
  • Sorry, what do you mean by "the difference between scripts"? `ENV['PATH'].split(':').collect {|d| Dir.entries d if Dir.exists? d}.flatten.include? 'g++'` returns true on my machine. – Xiong Chiamiov Jun 05 '10 at 01:13
  • I tested it on windows xp, and it didn't work. Had the following line in a file: puts ENV['PATH'].split(':').collect {|d| Dir.entries d if Dir.exists? d}.flatten.include? 'gcc'. Returned false. From the command line gcc --version is: gcc (TDM-2 mingw) 4.4.1 and ruby --version is: ruby 1.9.1p376. – srcspider Jun 08 '10 at 07:53
  • I think that the PATH separator on Windows is `;`, rather than `:`. If you pop into `irb` and take a look at `ENV['PATH']` you'll find out. – Xiong Chiamiov Jun 11 '10 at 17:36
1

i've required something similar (is it executable in the path) and use the system command but check the error code of return. according to this its a standard result in unix (127 = file not found) stackoverflow standard unix return codes

    def checkinstalled(program)
      stdop=system(program)
      result=$?
      exit_code=result.exitstatus 
      return !exit_code.eql?(127)
    end

can't say for windows however

Community
  • 1
  • 1
Ben
  • 1,292
  • 1
  • 13
  • 21