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
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
3 Comments
: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?[:out, :err] => File::NULL, as well as many other things.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
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./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.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
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
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.
1 Comment
IO.popen('cmd').close work as well? stackoverflow.com/questions/1217351/…- define
null_device, it's operating systems dependent: windows 7 and newer usenul, 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
You can also use backticks or %x
3 Comments
This should work
system ls, STDOUT:'/dev/null'