Ruby Open3.popen3 simulate user input - ruby

I am trying to run a bash script (#command) that requires user input and I'm trying to feed that script input using the following code:
Open3.popen3(#command) do |stdin, stdout, stderr|
stdin.write("y")
stdout.gets
end
Here is an idea of the script:
exec sudo su -c "some command" $username
If anyone could tell me what I am doing wrong or has any suggestions on how to implement this a different way, that would be much appreciated.
Also, I can run the script like this:
#output = `#{#command}`
In this case, I can see the contents of the script output in the console I am running my app from. If there is anyway to feed input to that location that would work too.

Got my solution here:
How to fix hanging popen3 in Ruby?
Open3.popen3(#command) do |stdin, stdout, stderr|
stdin.puts "y\r\n"
stdout.each_line { |line| puts line }
stdin.close
end

out_err, status = Open3.capture2e(#command, :stdin_data => "y\r\n")
print out_err

Related

Ruby - Running rb files from script (2)

I'd like to write a ruby script that then calls another ruby script. Example, I'd like to run the "test1.rb" from my script. The test1.rb has been simplified to just do this:
print "1"
Then get the result (-> 1).
I ask to help others to fix this problem, and they suggested the popen3 command:
require 'open3'
cmd = 'ruby "test1.rb"'
puts Dir.pwd
Open3.popen3(cmd) do |stdin, stdout|
var = stdout.read
puts var
end
However, the script send an error message:
X:/Ruby22-x64/lib/ruby/2.2.0/open3.rb:193:in `spawn': No such file or directory
- ruby "test1.rb" (Errno::ENOENT)
Please help me.

ruby - getting system command stdout with popen3 not working

I am using lftp to download some files. Below is the code I'm using and I'd like to capture the stdout. It doesn't show anything though.
If I just run the command in bash I get streaming progress to stdout. I know its stdout because if I redirect 1 > /dev/null then the output stops.
Can anyone help please tell me if it's possible to capture stdout of this program?
Open3.popen3("lftp -vvv -c 'pget -n 10 ftp://mirror.us.leaseweb.net/debian-cd/7.4.0-live/i386/iso-hybrid/debian-live-7.4-i386-xfce-desktop.iso'") do |stdin, stdout, stderr|
stdout.sync = true
stdout.each { |line| puts line }
stderr.each { |line| puts line }
end
UPDATE: looking through the lftp code it uses a '\r' carriage return to have the stdout rewind to start of same line and update rather then take a new line for each. Maybe open3 can't cope well with this.

How do I to run a command in Linux as a Ruby script?

Let's say I have some terminal commands like:
sudo mycommand1
mycommand2
#.....
What should I do run them via ruby script (not bash) in Ubuntu?
UPDATE:
I have a ruby script:
def my_method1()
#calculating something.....
end
def method2(var1, var2)
#how do I sudo mycommand1 and any other Lunix command from here?
end
def method3(var4)
#calculating something2....
end
You can do system, exec, or place the command in backticks.
exec("mycommand") will replace the current process so that's really only pratical at the end of your ruby script.
system("mycommand") will create a new process and return true if the command succeeded and nil otherwise.
If you need to use the output of your command in your Ruby script use backticks:
response = 'mycommand`
There are many questions on SO that answer this. However you can run a command in many ways using system, exec, (backticks), %x{} or using open3. I prefer to use open3 -
require 'open3'
log = File.new("#{your_log_dir}/script.log", "w+")
command = "ls -altr ${HOME}"
Open3.popen3(command) do |stdin, stdout, stderr|
log.puts "[OUTPUT]:\n#{stdout.read}\n"
unless (err = stderr.read).empty? then
log.puts "[ERROR]:\n#{err}\n"
end
end
If you want to know more about other options you can refer to Ruby, Difference between exec, system and %x() or Backticks for links to relevant documentation.
You can try these approaches:
%x[command]
Kernel.system"command"
run "command"
make some file.rb with:
#!/path/to/ruby
system %{sudo mycommand1}
system %{mycommand2}
and the chmod the file with exec permissions (e.g. 755)
It you need to pass variables between the two commands, run them together:
system %{sudo mycommand1; \
mycommand2}

Running a shell command from Ruby: capturing the output while displaying the output?

I have a problem.
I want to run a ruby script from another ruby script and capture it's output information while letting it output to the screen too.
runner
#!/usr/bin/env ruby
print "Enter your password: "
password = gets.chomp
puts "Here is your password: #{password}"
The script file that I run:
start.rb
output = `runner`
puts output.match(/Here is your (password: .*)/).captures[0].to_s
As you see here there is a problem.
In the first line of start.rb the screen is empty.
I cannot see the "Enter your password: " in runner.
Is there a way to display the output of the runner script before it's finished, and still let me capture it to a string so I can process the information, eg. using match like in this example?
runner.rb
STDOUT.print "Enter your password: "
password = gets.chomp
puts "Here is your password: #{password}"
Note STDOUT.print
start.rb
require "stringio"
buffer = StringIO.new
$stdout = buffer
require "runner"
$stdout = STDOUT
buffer.rewind
puts buffer.read.match(/Here is your (password: .*)/).captures[0].to_s
output
Enter your password: hello
password: hello
Read more...
I recently did a write-up on this here: Output Buffering with Ruby
Try this:
rd, wr = IO::pipe
pid = Process.fork do
$stdout.reopen(wr)
rd.close
exec("command")
end
wr.close
rd.each do |line|
puts "line from command: #{line}"
end
Process.wait(pid)
Similar if you want to capture stderr. If you need to capture both it would a bit more difficult (Kernel.select?)
Edit: Some explanation. This is an ancient Unix procedure: pipe + fork + calls to dup2 (reopen) depending on what you want. In a nutshell: you create a pipe as a means of communication between child and parent. After the fork, each peer close the pipe's endpoint it does not use, the child remaps (reopen) the channel you need to the write endpoint of the pipe and finally the parent reads on the read channel of the pipe.
For script independent output logging you might want to enable it from the terminal emulator (shell container).
screen -L
OR
xterm -l
This will capture all output produced by any shell or program running inside the emulator, including output generated by your ruby scripts.
You could use tee to write the contents to a file or a pipe, and read the file afterwards.
Have a look at POpen4.
It claims to be platform independent (but I do not think it works in jruby where you can use IO#popen instead).
Have your script do its prompt output to stderr.
echo "Enter something" >&2
read answer
echo "output that will be captured"
This will be done for you if you use read -p to issue the prompt:
read -p "Enter something" answer
echo "output that will be captured"
io = IO.popen(<your command here>)
log = io.readlines
io.close
Now in log variable you have the output of executed command. Parse it, convert it, or do whatever you want.

In Ruby, what is the best way to execute a local Linux command stored in a string?

In Ruby, what is the simplest way to execute a local Linux command stored in a string while catching any potential exceptions that are thrown and logging the output of the Linux command and any thrown errors to a common log file?
I faced the same question before, and "Process management" answered all my needs.
If you don't want to separate the error from normal output just use popen:
output = IO.popen("other_program", "w+") do |pipe|
pipe.puts "here, have some input"
pipe.close_write
pipe.read
end
but if you do want to, use popen3:
Open3.popen3('nroff -man') { |stdin, stdout, stderr| ... }
look at IO.popen
If you want to execute ls -a:
%x[ls -a]
Here is the code I use to see whether a process is active:
systemOutput=`ps -A | grep #{process_to_look_for}`
if systemOutput.include? process_to_look_for
puts "#{process_to_look_for} is already running"
exit
end

Resources