"ruby script.rb" versus "xterm -e ruby script.rb" - ruby

I've run into a strange problem with Ruby that I can't explain. I have the following script that grabs whatever code is currently in the clipboard, runs it through a syntax highlighter, then puts the new version BACK into the clipboard:
#!/usr/bin/ruby1.9.1
require 'coderay'
language = "auto";
if(ARGV.length > 0)
language = ARGV[0];
end
print("Using language: #{language} \n");
codeToHighlight = `xsel --clipboard`
highlightedCode = CodeRay.scan(codeToHighlight, language.intern()).div
IO.popen("xsel --clipboard", mode='w') do |io|
io.write highlightedCode
io.flush
end
The odd part is that if I run it directly within a terminal, it works fine. If I run it via "xterm -e", however, it doesn't work. I found this thread on another site that asked the same question, but the person never got an answer: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/138423
That person found that if they added a pause at the end of the script like so...
10000.times do
puts ""
end
...it works. Why is this? Is there a way to fix this? I tried rewriting the script so that the popen returns an IO object and I could manually call close, but that doesn't make a difference.

How about if you execute it with gnome-terminal -e instead of xterm -e?
UPDATE:
OK, here is my best guess. You know how if you send a terminal program to the background (either with & after the command or with ctl-z) and then you close the terminal it kills the program, right? Well, xsel forks a child process to write to the clipboard, but it must be getting killed when the ruby wrapper script finishes and and xterm closes.
That would explain why the pause at the end allows it to work - it just gives enough time for the child process to finish before the terminal quits. It also explains why it works when run manually - you leave the terminal open long enough for the child process to finish.
Try adding the -n option to your xsel command, and I bet it works. -n keeps xsel from forking.

Related

Ruby run external program stops script

I have a ruby script that midway through I need it to run another program.
After running the program the rest of the script doesnt get run. For example:
# some ruby that gets run
exe = "Something.exe"
system(exe)
# some ruby that doesnt run
I have also tried using Open3.popen2e(cmd) and Open3.popen3(cmd) but its the same.
Can anyone help me understand what is happening here and how to fix it?
note: I'm using windows
Try to run Something.exe in a new Thread:
Thread.new { system("Something.exe") }
In case you want to run your System.exe asynchronously and continue without waiting it to be finished, you could use spawn or multithreading.
pid = spawn('System.exe')
Process.detach(pid)
According to this previous answer, this should work on Windows as well (while fork or other methods don't).
In this article you can find several examples using system, exec, fork, spawn and Thread on Unix.
I cannot reproduce it, but it could be worth to see if using system("start System.exe") works on windows like system("cmd &") works on UNIX. You can refer to start documentation here.

Ruby can't read TCP socket when run in background

I was writing a Slack bot in Ruby under Windows and everything worked just fine until I decided to run it on a Linux server. When I access my shell and run the script it works correctly in the foreground, but once I move it to the background it stops working. I'm getting a timeout error on a HTTP request with Net::HTTP, or an EOFError on the socket read.
I'm using Ruby 2.3 on Debian 7.
I think that the Ruby process stops on its own, because I only get the errors once I return the process to the foreground, and, if I run ps aux when the process is in the background it has the "T" (stopped) flag listed.
Since I want to become more familiar with Linux, I'd like to know what is causing the issue, rather than how to solve it.
EDIT: I found that my user input handler is causing the problem. Here is the problematic bit:
def input_handler
return Thread.new {
loop do
user_input = gets.chomp
end
}
end
The problem looks like it's gets.
By default gets reads from STDIN. The documentation says:
Returns (and assigns to $_) the next line from the list of files in ARGV (or $*), or from standard input if no files are present on the command line.
The code/thread will stop and wait for a prompt from the keyboard, or read from the piped input if STDIN is redirected or from a file given as a parameter to the script on the command-line.

Ruby: Keep console open after script execution

I wrote a Ruby script like the following example. The basic functionality is the same:
# get input from the user
input = gets.chomp
# do awesome stuf with this input and print the response
puts do_awesome_stuff(input)
The problem is when I run the script it prints the solution I want, but the console window closes right after. I want the console to keep open.
I'm currently on windows, but the solution should be working on every system.
One way is to run the ruby script with a .bat file and pause it, like so:
ruby script.rb
PAUSE
I hope there is a way without the additional .bat file. Does Ruby has a function like PASUE integrated?
It seems like you double click the ruby script file.
Instead issue the following command in cmd shell.
ruby filename.rb
If you don't want that, you can add gets to the end of the script.
# get input from the user
input = gets.chomp
# do awesome stuf with this input and print the response
puts do_awesome_stuff(input)
gets # <----
But this is not recommended because .. if you run the command in cmd shell or terminal you should type extra Enter to return to the shell.
Use the -r options of irb.
irb -r ./filename.rb

Piping stdin to ruby script via `myapp | myscript.rb`

I have an app that runs continuously, dumping output from a server and sending strings to stdout. I want to process this output with a Ruby script. The strings are \n-terminated.
For example, I'm trying to run this on the command line:
myapp.exe | my_script.rb
...with my_script.rb defined as:
while $stdin.gets
puts $_
end
I ultimately am going to process the strings using regexes and display some summary data, but for now I'm just trying to get the basic functionality hooked up. When I run the above, I get the following error:
my_script.rb:1:in `gets': Bad file descriptor (Errno::EBADF)
from my_script.rb:1
I am running this on Windows Server 2003 R2 SP2 and Ruby 1.8.6.
How do I continuously process stdin in a Ruby script? (Continuously as in not processing a file, but running until I kill it.)
EDIT:
I was able to make this work, sort of. There were several problems standing in my way. For one thing, it may be that using Ruby to process the piped-in stdin from another process doesn't work on Windows 2003R2. Another direction, suggested by Adrian below, was to run my script as the parent process and use popen to connect to myapp.exe as a forked child process. Unfortunately, fork isn't implemented in Windows, so this didn't work either.
Finally I was able to download POpen4, a RubyGem that does implement popen on Windows. Using this in combination with Adrian's suggestion, I was able to write this script which does what I really want -- processes the output from myapp.exe:
file: my_script.rb
require 'rubygems'
require 'popen4'
status =
POpen4::popen4("myapp.exe") do |stdout, stderr, stdin, pid|
puts pid
while s = stdout.gets
puts s
end
end
This script echoes the output from myapp.exe, which is exactly what I want.
Try just plain gets, without the $stdin. If that doesn't work, you might have to examine the output of myapp.exe for non-printable characters with another ruby script, using IO.popen.
gets doesn't always use stdin but instead tries to open a file.
See SO.
Try executing your Ruby script by explicitly calling ruby:
myapp.exe | ruby my_script.rb
I've experienced some odd behavior using stdin in Ruby when relying on Windows to invoke the correct program based on the file associations.

How can I do something later, but get the applescript to return now?

I have an applescript that does something similar to:
using terms from application "iChat"
on logout finished
delay 30
… do some stuff
end logout finished
end using terms from
The problem with this script, is that it also blocks the application calling it for the 30 seconds. What I would like to do then is say something like "in thirty seconds, please run this script for me", and then move all of my … do some stuff to that other script. But I can't see how to do that?
Any suggestions?
Since you are using a Mac, I assume you have Ruby installed.
What you are talking about sounds like you want a thread to sleep for 30 seconds and then execute a script in the background.
You should put … do some stuff in a script named dostuff.scpt and place it in your Desktop.
Then change your current script to the following code:
using terms from application "iChat"
on logout finished
do shell script "ruby -e 'Thread.new {`sleep 30 && osascript ~/Desktop/dostuff.scpt`}' &> /dev/null"
end logout finished
end using terms from
A code breakdown:
do shell script (executes something from the command line)
ruby -e (executes ruby code from the command line)
Thread.new (makes a new thread to hide in the background)
` (Everything in the backtick is a shell command in ruby)
osascript (Executes an applescript from the command line)
~/Desktop/dostuff.scpt (Points the pathname to your file, the tilde substitutes to your home directory, and I assume you put dostuff.scpt on the Desktop)
&> /dev/null (Tells Applescript to not look for output and immediately go to the next code line)
I tried doing this without Ruby, however, I had no luck. Let me know if this works for you!

Resources