Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Suppressing the output of a command run using 'system' method while running it in a ruby script

Tags:

ruby

I am not sure if this makes sense but I am thinking if there is a way to suppress the output shown for a command when run using the system method in ruby? I mean it should just output true or false to STDOUT and not the output of the command. What I think is it can just only be done if the command can run silently and not from the system method. Can someone provide a bit more insight?

like image 960
kilari Avatar asked Dec 25 '09 09:12

kilari


People also ask

What is ruby command?

Ruby command is a free and open source programming language; it is flexible and is feature rich. As the name suggests, ruby indeed is a jewel language which comes at a very low entry cost. Its plug and play capability and also easily readable syntax makes it very user-friendly.


3 Answers

If you want to take advantage of the variadic form of Kernel.system, which side-steps the many quoting issues with shells, you can use the same options which Kernel.spawn accepts.

TL;DR - Use :out => File::NULL to silence output from Kernel.system

Arguments with special characters (spaces, etc.) can cause problems with the shell:

irb(main):001:0> filename_with_spaces = "foo bar.txt"
=> "foo bar.txt"

irb(main):002:0> system "ls -l #{filename_with_spaces}"
ls: bar.txt: No such file or directory
ls: foo: No such file or directory
=> false

So if you are interpolating variables into a system call, it is safer to provide the arguments separately:

irb(main):003:0> system "ls", "-l", filename_with_spaces
-rw-r--r--  1 nobody  nobody  9 Feb  1 16:53 foo bar.txt
=> true

But now we have a problem if we want to hide the output.

irb(main):004:0> system "ls", "-l", filename_with_spaces, "> /dev/null"
ls: > /dev/null: No such file or directory
-rw-r--r--  1 nobody  nobody  9 Feb  1 16:53 foo bar.txt
=> false

We could close STDOUT using the :out => :close option:

irb(main):005:0> system "ls", "-l", filename_with_spaces, :out => :close
=> true

However, this might cause issues with certain commands which may try to attach to STDOUT.

irb(main):006:0> system "echo", "hi there", :out => :close
echo: write: Bad file descriptor
=> false

To fix this, we can go back to redirecting our output, using File::NULL to remain portable:

irb(main):007:0> system "echo", "hi there", :out => File::NULL
=> true
like image 192
Steve Avatar answered Oct 21 '22 22:10

Steve


After a call to system the exit code is in the special variable $? so if useradd returns different values to indicate if the user was successfully added (e.g. 0 for success) then you can do the following:

system('useradd xx > /dev/null')
if $? == 0
  puts 'added'
else
  puts 'failed'
end

where the redirect to /dev/null will suppress the output.

Alternatively if the program being called does not use its exit code to indicate success or failure you can use backticks and search for a particular substring in the output e.g.

if `useradd xx`.include? 'success'
  puts 'it worked'
else
  puts 'failed to add user'
end
like image 42
mikej Avatar answered Oct 21 '22 22:10

mikej


As an addendum, I've been surprised a few times when I've used backticks and saw output "slipping past" my variables when running scripts from the command line.

Invariably, the issue is that the text I'm seeing is actually coming from stderr rather than stdout. So, to wrangle that text into stdout as well, remember to append 2>&1 to the command you're trying to run.

I hope that's helpful to someone. I just wasted twenty minutes re-learning this lesson :)

like image 8
Chris Allen Lane Avatar answered Oct 21 '22 21:10

Chris Allen Lane