40

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?

8 Answers 8

67

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
Sign up to request clarification or add additional context in comments.

3 Comments

From this answer I was able to deduce :err => as well. Is there something that means both out: and :err, so I don’t have to write :out => File::NULL, :err => File::NULL?
If you look at documentation for Kernel#spawn, you'll find that you can do this [:out, :err] => File::NULL, as well as many other things.
@Steve Goddamn that's elegant AF.
23

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

3 Comments

This alone won't suppress stderr. Should use this system('useradd xx > /dev/null 2>&1')
system also returns true or false and I especially like to depend on those simple values. The return values are not affected by the > /dev/null 2>&1 redirection.
None of these will work on Windows because /dev/null doesn't exist, even under Git-Bash. The better answer is to use out: File::NULL, err: File::NULL. That's properly portable and clearly indicates intent without having to worry about if you handled &2>1 vs. &> vs whatever.
8

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 :)

Comments

2

I was faced with this question as well...

Keep in mind that with ruby system calls, the UNIX command you are trying to use might offer a "silent" option--nullifying the need to suppress terminal output altogether!

For instance:

system 'curl -s "your_params_here"'

Will suppress the output that typically accompanies a curl call.

Comments

1

IO.popen

This is another good option:

IO.popen(['echo', 'a']) do |f|
  f.read == "a\n" or raise
end
$?.exitstatus == 0 or raise

Nothing will get output to your stdout.

http://www.ruby-doc.org/core-2.1.4/IO.html#method-c-popen

1 Comment

TODO does IO.popen('cmd').close work as well? stackoverflow.com/questions/1217351/…
0
  • define null_device, it's operating systems dependent: windows 7 and newer use nul, while *nix systems uses /dev/null
  • run the command
  • redirect it's standard and error output to null_device
  • then use the exit code, or the backtick method as mentioned by @mikej to determine the output

as follows:

 null_device = Gem.win_platform? ? "/nul" : "/dev/null"

 do method
   system "run command 1>#{null_device} 2>#{null_device} "
   p ($? == 0)
 end

1 Comment

Doesn't work, still shows the output
-2

You can also use backticks or %x

3 Comments

yes but I will not be able to use it as a condition to execute a few statements which I can do when using 'system'
That makes very little sense so maybe you should post an actual example.
So write a different conditional that actually parses the output and might be a better idea than what you have now.
-4

This should work

system ls, STDOUT:'/dev/null'

1 Comment

This is an invalid argument, so no idea where this comes from.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.