how to interupt a program trying to open a file - ruby

We are making a program write to a file on my computer and there is basically just one part that I can't figure out how it works.
Before the program opens the file the program allows me to press the Return key to go ahead to open the file and thus erasing the content. Or I can press ctrl+C to interrupt my program. I'm thankful for any kind of input here since I really can't seem to find anything about this specific function.
filename = ARGV.first
puts "We're going to erase #{filename}"
# This is the part I can't find out how it works.
puts "If you dont want that press ctrl-c (^C)."
puts "If you do want that press RETURN."
$stdin.gets

Ruby gets reads a line of text. When called on a file - it reads a line of this file. When called on $stdin as in your case, it reads a line from the standard input (a console).
If you press Enter, the program will read an empty line and continue execution. If you press Ctrl+C a signal is sent to the program and this signal make program to stop execution. You can press Ctrl+C in any moment of program execution and it will be stopped (unless the signal is handled in the program, but it's not the case here).
See also:
gets docs
question about Ctrl-C

Related

Alert on operation completion in windows cmd

Using windows cmd I have to put large programs on compilation which take large amount of time. Everytime to know whether operation is complete or not I have to check cmd again and again. I want to know whether there is way by which I can make changes to cmd such that it gives me a signal that operation has been completed by playing sound or by opening a dialog etc.
Please share if anyone has some idea
There can be many ways to achieve this
This is the easiest
While your code is compiling (ie compiling has just began) in the same cmd prompt
type " ctrl + G " and press enter this will go to the input stream of cmd and will wait there until it can be executed , ctrl +G is the BEL character which gives you a single beep when you execute it .
You can also enter multiple BEL characters to get multiple beeps upon completion of the task.
A harder way could be , to write a python script that executes the compilation command say "g++ my_prog.cpp" and upon completion plays a sound or give you a simple popup notification via a windows message box.
Include in yout batch file
msg console /time:3600 "The task has ended"
Send a message to the console and keep it open (if not closed by the user) 3600 seconds (if not indicated there is a 60 seconds timeout).

How can I check for keyboard input without stopping execution?

What command/keyword is used to check for keyboard input without stopping execution? I want to build a loop that will run continuously, and at every iteration of the loop, I want to check for keyboard input. If the user presses the right key, my program will act on it; if not, it will continue to run.
EDIT
I want it to work with out pressing the enter key. Like when a game runs it checks if the user presses the arrow key then acts on the key press or continues if nothing is pressed.
From what I could find and some hacking around, I managed to put together something that will immediately echo the keys you press when running in command line.
require 'io/console'
loop do
p STDIN.getch
end
But as the referenced answer mentions, you'll want to capture SIGTERMs so you don't get trapped in the program: Signal.trap("INT") { exit }
So the meat of your program and all of its processing lives in that main loop, and each go around of that loop it will grab a character from the STDIN.
You cannot do that with a simple method. The most common way to do that is to use the curses gem.

Redirect command line input to file, then turn over to standard input

I have a command-line program that I would like to launch, execute a few commands automatically, and then turn the input over to the standard input. The problem with using command line input redirection is that as soon as the commands execute, the program quits. Instead of quitting immediately, I'd like to take over control from that point.
Is there any way to do this? I haven't been able to find anything that works.

Can I trap control-q and control-s in ruby?

For some signals, like SIGINT, I can easily enough set up a trap to handle the signal and continue execution as I see fit. I'd like to add typical behavior for ^q and ^s to a ruby command-line application that I'm fiddling with. Is there a way to do this - particularly, one that is portable so I can use it in Windows, iOS, Linux and Solaris?
EDIT:
It turns out that the signals are never delivered to the process. In fact, running strace on the process and on its parent process, a bash instance, showed that neither the process nor the parent were getting any indication of what was going on. They're simply being suspended.
I may try to have a SIGALARM handler that fires once per second, checks to see if much more than a second has passed since the last alarm, and makes appropriate calls if it concludes that the process has been suspended. There would be false positives on a heavily-loaded system.
In irb enter Signal.list. It will list all the signals you should be able to trap.
Trap a signal in ruby:
Signal.trap("STOP") do
# handle the signal
end
In the terminal enter $ stty -a. It should list signals and their associated key combo (if they have one).
I believe ^s is usually stop and ^q is start.
Although according to this answer, those key combos do not actually send a signal to the running process, but instead to the terminal driver. In that case, kill -STOP <process> can send that signal to your process.
TL;DR No, you can't trap them, because they don't result in signals and the processes under the terminal don't see them and can only detect them heuristically. However, if the point is to be able to use those keybindings in your terminal program, then yes, you can do that by disabling the terminal's special treatment of them.
^q and ^s don't result in signals. It's ^z not ^s that results in the terminal signaling SIGSTOP (EDIT: It's actually SIGTSTP).
What ^s does is tell the terminal to not read the output of the processes that are writing to it. This causes the processes to block on write to the terminal (they can still write to other places and read from stdin, as well as do other things)[1]. ^q tells the terminal to continue reading and displaying the processes output. The processes that have the terminal as standard input don't see these. The terminal sees the keybindings, acts on them, and doesn't pass them on to the processes reading from its terminal device.
You can disable this special behaviour with stty -ixon, and re-enable it with stty ixon. When I disable it, the process that reads while I type says that ^s is byte 0x13, and ^q is byte 0x11.
[1] As an experiment to show this, you can open 2 terminal windows. Execute tty on the second one to find its terminal device. Then, on the first terminal, you can run tee $TTY > $OTHER_TTY with $OTHER_TTY being the terminal device of the second terminal. Once you've done that, you can hit ^s to block writes to the terminal and check this by typing some line. That line will be displayed in the second terminal, but not the first, and thereafter nothing you type will be displayed on either until you hit ^q. What happened here is that after you hit ^s and typed a line, tee could still read it, and output it to its stdout which we redirected to the second terminal. Then, when it tried to write it to the first file passed as argument it blocked because it was the terminal you blocked with ^s. It stayed there waiting for write() to return which it won't until you hit ^q.

Why might ruby fail to recognize that a child process (opened using popen) has terminated?

The child process is launched using the following code:
IO.popen("/path/to/process/in/question") do |command|
command.each do |line|
puts line
end
end
puts "Child Process Complete"
The individual lines output by the child process are correctly shown on the console up to and including one immediately before the process exits. However, the message "Child Process Complete" is not shown until I hit ctrl-c.
A similar process, triggered using the same mechanism, is correctly recognized as having terminated, so the problem is probably a result of something that the child process is doing. Unfortunately I have no idea what that something may be.
[Edit] I should probably also mention that the child process can also be triggered directly from the command prompt, and that no issues are observed when doing so.
Benoit Garret put me onto the right track when he suggested that something was waiting for user input. In attempting to sanitize the child process script (and the things it called in turn) I stumbled upon what appeared to be an error in a script lower down (which has been sitting there unnoticed for several years).
The Ruby code, posted above made a call to an initial shell script. That in turn was calling a second shell script which contained the following abomination:
(some_application) &
>/dev/null 2>&1
I'm not sure if this is what happened, but the way I read this is that some_application gets started and run as a background process. Standard output gets redirected to /dev/null and standard error gets redirected to standard output... but which process does this redirection relate to?
Changing the call to
some_application >/dev/null 2>&1 &
(I.e. run some_application throwing away standard out and capturing standard error to the console) made all my problems go away.

Resources