Is there a way to run a ruby script and while executing commands in the script ,still respond to key stroke ?
有没有办法运行ruby脚本并在脚本中执行命令时仍然响应键击?
I want to run a ruby script but be able to press "Space" and pause the script (after currently running command executes ), and then press "Space" again and resume the script .
我想运行ruby脚本,但能够按“Space”并暂停脚本(在当前运行命令执行后),然后再次按“Space”并恢复脚本。
My only idea (and im sure its a weird one) , is to open a new thread and wait for key strokes there , then when ill get a key stroke , set a stop_flag. Only now it looks like i need to be checking this flag after each command to know when to stop.
我唯一的想法(并且我确定它是一个奇怪的想法),是打开一个新线程并等待那里的击键,然后当生病得到一个击键时,设置一个stop_flag。只是现在它看起来我需要在每个命令后检查此标志以知道何时停止。
3 个解决方案
#1
1
You can use a signal to turn debug output on and off at will, if you have a logger set up with appropriate code sprinkled throughout your script:
如果您在整个脚本中设置了适当的代码,则可以使用信号随意打开和关闭调试输出:
pid = fork do
# set up a logger
require 'logger'
log = Logger.new(STDOUT)
log.level = Logger::INFO
# toggle between INFO and DEBUG log levels on SIGUSR1
trap(:SIGUSR1) do
if log.level == Logger::DEBUG
log.level = Logger::INFO
else
log.level = Logger::DEBUG
end
end
# Main loop - increment a counter and occasionally print progress
# as INFO level. DEBUG level prints progress at every iteration.
counter = 0
loop do
counter += 1
exit if counter > 100
log.debug "Counter is #{counter}"
log.info "Counter is #{counter}" if counter % 10 == 0
sleep 0.1
end
end
# This makes sure that the signal sender process exits when the
# child process exits - only needed here to make the example
# terminate nicely.
trap(:SIGCLD) do
exit(0) if Process.wait(-1, Process::WNOHANG) == pid
end
# This is an example of sending a signal to another process.
# Any process may signal another by pid.
# This example uses a forking parent-child model because this
# approach conveniently yields the child pid to the parent.
loop do
puts "Press ENTER to send SIGUSR1 to child"
STDIN.gets
Process.kill :SIGUSR1, pid
end
The forking and SIGCLD trapping is to make the example fit into one file; any process may send a signal to another.
分叉和SIGCLD陷阱是使示例适合一个文件;任何进程都可以向另一个进程发送信号。
The code inside the fork block is your script. The script sets up a logger with a default log level of INFO, and a handler for the SIGUSR1 signal that toggles the logger between DEBUG and INFO levels.
fork块中的代码是您的脚本。该脚本设置一个记录器,其默认日志级别为INFO,以及一个SIGUSR1信号处理程序,用于在DEBUG和INFO级别之间切换记录器。
The stuff outside of the fork block is just an example of sending a signal to another process. Pressing ENTER will send the signal and alter the logging level of the other process.
fork块之外的东西只是向另一个进程发送信号的一个例子。按ENTER将发送信号并更改其他进程的日志记录级别。
This works on POSIX systems, I have no idea about Windows.
这适用于POSIX系统,我不知道Windows。
#2
1
Similar idea to @Catnapper, I thought I'd share it although he beat me to the punch.
与@Catnapper类似的想法,我以为我会分享它虽然他打败了我。
require 'io/console' # Ruby 1.9
# Wait for the spacebar key to be pressed
def wait_for_spacebar
sleep 1 while $stdin.getch != " "
end
# Fork a process that waits for the spacebar
# to be pressed. When pressed, send a signal
# to the main process.
def fork_new_waiter
Process.fork do
wait_for_spacebar
Process.kill("USR1", Process.ppid)
end
end
# Wait for a signal from the forked process
Signal.trap("USR1") do
wait_for_spacebar
# Debug code here
fork_new_waiter
end
# Traps SIGINT so the program terminates nicely
Signal.trap("INT") do
exit
end
fork_new_waiter
# Run program here in place of this loop
i = 0
loop do
print i+=1
sleep 1
end
#3
1
You can use a system command.
您可以使用系统命令。
In Windows use: system "pause>null"
在Windows中使用:系统“pause> null”
This would be different for each OS. So, you could set a variable to check the OS. Then use the appropriate command. If you want to see if the OS is Windows, your code would look like this:
对于每个OS,这将是不同的。因此,您可以设置变量来检查操作系统。然后使用适当的命令。如果您想查看操作系统是否为Windows,您的代码将如下所示:
if RUBY_PLATFORM =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/ $operatingSystem="win" end
如果RUBY_PLATFORM =〜/ mswin | msys | mingw | cygwin | bccwin | wince | emc / $ operatingSystem =“win”end
#1
1
You can use a signal to turn debug output on and off at will, if you have a logger set up with appropriate code sprinkled throughout your script:
如果您在整个脚本中设置了适当的代码,则可以使用信号随意打开和关闭调试输出:
pid = fork do
# set up a logger
require 'logger'
log = Logger.new(STDOUT)
log.level = Logger::INFO
# toggle between INFO and DEBUG log levels on SIGUSR1
trap(:SIGUSR1) do
if log.level == Logger::DEBUG
log.level = Logger::INFO
else
log.level = Logger::DEBUG
end
end
# Main loop - increment a counter and occasionally print progress
# as INFO level. DEBUG level prints progress at every iteration.
counter = 0
loop do
counter += 1
exit if counter > 100
log.debug "Counter is #{counter}"
log.info "Counter is #{counter}" if counter % 10 == 0
sleep 0.1
end
end
# This makes sure that the signal sender process exits when the
# child process exits - only needed here to make the example
# terminate nicely.
trap(:SIGCLD) do
exit(0) if Process.wait(-1, Process::WNOHANG) == pid
end
# This is an example of sending a signal to another process.
# Any process may signal another by pid.
# This example uses a forking parent-child model because this
# approach conveniently yields the child pid to the parent.
loop do
puts "Press ENTER to send SIGUSR1 to child"
STDIN.gets
Process.kill :SIGUSR1, pid
end
The forking and SIGCLD trapping is to make the example fit into one file; any process may send a signal to another.
分叉和SIGCLD陷阱是使示例适合一个文件;任何进程都可以向另一个进程发送信号。
The code inside the fork block is your script. The script sets up a logger with a default log level of INFO, and a handler for the SIGUSR1 signal that toggles the logger between DEBUG and INFO levels.
fork块中的代码是您的脚本。该脚本设置一个记录器,其默认日志级别为INFO,以及一个SIGUSR1信号处理程序,用于在DEBUG和INFO级别之间切换记录器。
The stuff outside of the fork block is just an example of sending a signal to another process. Pressing ENTER will send the signal and alter the logging level of the other process.
fork块之外的东西只是向另一个进程发送信号的一个例子。按ENTER将发送信号并更改其他进程的日志记录级别。
This works on POSIX systems, I have no idea about Windows.
这适用于POSIX系统,我不知道Windows。
#2
1
Similar idea to @Catnapper, I thought I'd share it although he beat me to the punch.
与@Catnapper类似的想法,我以为我会分享它虽然他打败了我。
require 'io/console' # Ruby 1.9
# Wait for the spacebar key to be pressed
def wait_for_spacebar
sleep 1 while $stdin.getch != " "
end
# Fork a process that waits for the spacebar
# to be pressed. When pressed, send a signal
# to the main process.
def fork_new_waiter
Process.fork do
wait_for_spacebar
Process.kill("USR1", Process.ppid)
end
end
# Wait for a signal from the forked process
Signal.trap("USR1") do
wait_for_spacebar
# Debug code here
fork_new_waiter
end
# Traps SIGINT so the program terminates nicely
Signal.trap("INT") do
exit
end
fork_new_waiter
# Run program here in place of this loop
i = 0
loop do
print i+=1
sleep 1
end
#3
1
You can use a system command.
您可以使用系统命令。
In Windows use: system "pause>null"
在Windows中使用:系统“pause> null”
This would be different for each OS. So, you could set a variable to check the OS. Then use the appropriate command. If you want to see if the OS is Windows, your code would look like this:
对于每个OS,这将是不同的。因此,您可以设置变量来检查操作系统。然后使用适当的命令。如果您想查看操作系统是否为Windows,您的代码将如下所示:
if RUBY_PLATFORM =~ /mswin|msys|mingw|cygwin|bccwin|wince|emc/ $operatingSystem="win" end
如果RUBY_PLATFORM =〜/ mswin | msys | mingw | cygwin | bccwin | wince | emc / $ operatingSystem =“win”end