Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 249 Vote(s) - 3.68 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Getting output of system() calls in Ruby

#11
Be aware that all the solutions where you pass a string containing user provided values to `system`, `%x[]` etc. are unsafe! Unsafe actually means: the user may trigger code to run in the context and with all permissions of the program.

As far as I can say only `system` and `Open3.popen3` do provide a secure/escaping variant in Ruby 1.8. In Ruby 1.9 `IO::popen` also accepts an array.

Simply pass every option and argument as an array to one of these calls.

If you need not just the exit status but also the result you probably want to use `Open3.popen3`:

require 'open3'
stdin, stdout, stderr, wait_thr = Open3.popen3('usermod', '-p', @options['shadow'], @options['username'])
stdout.gets(nil)
stdout.close
stderr.gets(nil)
stderr.close
exit_code = wait_thr.value
Note that the block form will auto-close stdin, stdout and stderr- otherwise they'd have to be [closed explicitly][1].

More information here:

[To see links please register here]


[1]:

[To see links please register here]


Reply

#12
I'd like to expand & clarify [chaos's answer][1] a bit.

If you surround your command with backticks, then you don't need to (explicitly) call system() at all. The backticks execute the command and return the output as a string. You can then assign the value to a variable like so:

output = `ls`
p output
or

printf output # escapes newline chars

[1]:

[To see links please register here]

Reply

#13

puts `date`
puts $?


Mon Mar 7 19:01:15 PST 2016
pid 13093 exit 0

Reply

#14
The straightforward way to do this correctly and securely is to use [`Open3.capture2()`](

[To see links please register here]

), [`Open3.capture2e()`](

[To see links please register here]

), or [`Open3.capture3()`](

[To see links please register here]

).

Using ruby's backticks and its `%x` alias are **NOT SECURE UNDER ANY CIRCUMSTANCES** if used with untrusted data. It is **DANGEROUS**, plain and simple:

untrusted = "; date; echo"
out = `echo #{untrusted}` # BAD

untrusted = '"; date; echo"'
out = `echo "#{untrusted}"` # BAD

untrusted = "'; date; echo'"
out = `echo '#{untrusted}'` # BAD

The `system` function, in contrast, escapes arguments properly **if used correctly**:

ret = system "echo #{untrusted}" # BAD
ret = system 'echo', untrusted # good

Trouble is, it returns the exit code instead of the output, and capturing the latter is convoluted and messy.

The best answer in this thread so far mentions Open3, but not the functions that are best suited for the task. `Open3.capture2`, `capture2e` and `capture3` work like `system`, but returns two or three arguments:

out, err, st = Open3.capture3("echo #{untrusted}") # BAD
out, err, st = Open3.capture3('echo', untrusted) # good
out_err, st = Open3.capture2e('echo', untrusted) # good
out, st = Open3.capture2('echo', untrusted) # good
p st.exitstatus

Another mentions [`IO.popen()`](

[To see links please register here]

). The syntax can be clumsy in the sense that it wants an array as input, but it works too:

out = IO.popen(['echo', untrusted]).read # good

- - -

For convenience, you can wrap `Open3.capture3()` in a function, e.g.:

#
# Returns stdout on success, false on failure, nil on error
#
def syscall(*cmd)
begin
stdout, stderr, status = Open3.capture3(*cmd)
status.success? && stdout.slice!(0..-(1 + $/.size)) # strip trailing eol
rescue
end
end

Example:

p system('foo')
p syscall('foo')
p system('which', 'foo')
p syscall('which', 'foo')
p system('which', 'which')
p syscall('which', 'which')

Yields the following:

nil
nil
false
false
/usr/bin/which <— stdout from system('which', 'which')
true <- p system('which', 'which')
"/usr/bin/which" <- p syscall('which', 'which')
Reply

#15
I didn't find this one here so adding it, I had some issues getting the full output.

> You can redirect STDERR to STDOUT if you want to capture STDERR using
> backtick.
>
> output = \`grep hosts /private/etc/* 2>&1\`

source:

[To see links please register here]

Reply

#16
While using backticks or popen is often what you really want, it doesn't actually answer the question asked. There may be valid reasons for capturing `system` output (maybe for automated testing). A little Googling [turned up an answer][1] I thought I would post here for the benefit of others.

Since I needed this for testing my example uses a block setup to capture the standard output since the actual `system` call is buried in the code being tested:

require 'tempfile'

def capture_stdout
stdout = $stdout.dup
Tempfile.open 'stdout-redirect' do |temp|
$stdout.reopen temp.path, 'w+'
yield if block_given?
$stdout.reopen stdout
temp.read
end
end

This method captures any output in the given block using a tempfile to store the actual data. Example usage:

captured_content = capture_stdout do
system 'echo foo'
end
puts captured_content

You can replace the `system` call with anything that internally calls `system`. You could also use a similar method to capture `stderr` if you wanted.

[1]:

[To see links please register here]

Reply

#17
Simplest solution to capture standard output into a variable named **val**:

val = capture(:stdout) do
system("pwd")
end

puts val

shortened version:

val = capture(:stdout) { system("ls") }


**capture** method is provided by
*active_support/core_ext/kernel/reporting.rb*

Simlarly we can also capture standard errors too with `:stderr`
Reply

#18
<!-- language-all: ruby -->

**You can use a gem, called *Frontkick***

Frontkick.exec("echo *")

And here is how to check and read it:

result = Frontkick.exec("echo *")

puts result.successful? #=> true if exit_code is 0
puts result.success? #=> alias to successful?, for compatibility with Process::Status
puts result.stdout #=> stdout output of the command
puts result.stderr #=> stderr output of the command
puts result.exit_code #=> exit_code of the command
puts result.status #=> alias to exit_code
puts result.exitstatus #=> alias to exit_code, for compatibility with Process::Status
puts result.duration #=> the time used to execute the command

Github

[To see links please register here]


Gem Page

[To see links please register here]

Reply

#19
Short answer for most convenient way is:

```ruby
stdout_str, stderr_str, status = Open3.capture3(cmd)
puts "exit status: #{status.exitstatus} stdout: #{stdout_str}"
```
Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through