与 运行 进程交互
Interaction with a running process
举个简单的例子:
Process.run("ping", {"google.com"}) do |proc|
proc.output.each_line { |line| puts line }
end
它运行一个进程,不断读取它的输出并将输出打印到标准输出。目前,当我按下一个键时,它只会与 运行 过程的输出一起出现,但我想进行某种键处理,这样我就可以管理 运行从键盘处理:停止它,或使用修改后的参数重新启动它。怎么做?
或者,为了缩小问题范围,如何使这个输出-输入对彼此非阻塞?目前它采取一个步骤,然后等待它的对手发生。
Process.run("ping", {"google.com"}) do |proc|
until proc.output.closed?
puts proc.output.gets
puts "Got key: #{STDIN.raw &.read_char}"
end
end
使用终端进行交互式输入并不像看起来那么简单。您可以尝试 STDIN.raw &.read_char
。但这是有限的,可能不会让你走得太远。
通常用于此的工具是readline
。 stdlib 中有 Crystal 绑定(参见 Readline
). They're currently undocumented, but should work. You could also try https://github.com/Papierkorb/fancyline,它是 readline
.
的纯 Crystal 实现
此示例展示了如何处理 STDIN 和单个 TCP 会话。这是通过将处理程序生成到纤程来实现的。使用 some lines more,您可以与多个客户端共享 bash 或 REPL 会话。
示例 1:长 运行 过程
#Long running Process, here an interactive shell for example
spawn do
begin
cmd = "bash -i"
Process.run(cmd, shell: true) do | p |
pp p
my.bashpid = p.pid
my.bashinputfd = p.input.dup #get copy of current fd
p.input.puts("exec 2>&1") #stderr > stdout
p.input.puts("echo connected to bash") #send to STDIN of bash
while line = p.output.read_line
puts line #send to STDOUT
#send output of shell process to all online clients
Mc.get_clients.each do |all|
all.puts (line) #send to Client
end
end
end
rescue exception
puts "Error: #{exception.message}"
puts "Shell process has ended, program exits"
exit
end
end
示例 2:
require "socket"
#public vars
channel = Channel(String).new
csocket = Socket.tcp(Socket::Family::INET)
socket_conn=false
puts "Welcome:"
spawn do
server = TCPServer.new("0.0.0.0", 9090)
loop do #handle tcp client reconnects - do forever
socket = server.accept
csocket = socket.dup
socket_conn=true
p! socket_conn
print "\r"
while line = socket.gets
channel.send(line)
end
socket_conn=false
p! socket_conn
print "\r"
end
end
spawn do #handle stdin input char by char - do until ctrl-c pressed
while (char = STDIN.raw &.read_char) != '\u{3}' #ctrl-c
channel.send(char.to_s)
end
channel.send('\u{3}'.to_s)
end
loop do #do until cttrl-c
r = channel.receive
if r == "\u0003" #handle ctrl-c from channel
break
end
p! socket_conn
print "\r"
p! r
print "\r"
if socket_conn
csocket.puts "got: #{r}"
end
puts "got: #{r}"
print "\r"
end
举个简单的例子:
Process.run("ping", {"google.com"}) do |proc|
proc.output.each_line { |line| puts line }
end
它运行一个进程,不断读取它的输出并将输出打印到标准输出。目前,当我按下一个键时,它只会与 运行 过程的输出一起出现,但我想进行某种键处理,这样我就可以管理 运行从键盘处理:停止它,或使用修改后的参数重新启动它。怎么做?
或者,为了缩小问题范围,如何使这个输出-输入对彼此非阻塞?目前它采取一个步骤,然后等待它的对手发生。
Process.run("ping", {"google.com"}) do |proc|
until proc.output.closed?
puts proc.output.gets
puts "Got key: #{STDIN.raw &.read_char}"
end
end
使用终端进行交互式输入并不像看起来那么简单。您可以尝试 STDIN.raw &.read_char
。但这是有限的,可能不会让你走得太远。
通常用于此的工具是readline
。 stdlib 中有 Crystal 绑定(参见 Readline
). They're currently undocumented, but should work. You could also try https://github.com/Papierkorb/fancyline,它是 readline
.
此示例展示了如何处理 STDIN 和单个 TCP 会话。这是通过将处理程序生成到纤程来实现的。使用 some lines more,您可以与多个客户端共享 bash 或 REPL 会话。
示例 1:长 运行 过程
#Long running Process, here an interactive shell for example
spawn do
begin
cmd = "bash -i"
Process.run(cmd, shell: true) do | p |
pp p
my.bashpid = p.pid
my.bashinputfd = p.input.dup #get copy of current fd
p.input.puts("exec 2>&1") #stderr > stdout
p.input.puts("echo connected to bash") #send to STDIN of bash
while line = p.output.read_line
puts line #send to STDOUT
#send output of shell process to all online clients
Mc.get_clients.each do |all|
all.puts (line) #send to Client
end
end
end
rescue exception
puts "Error: #{exception.message}"
puts "Shell process has ended, program exits"
exit
end
end
示例 2:
require "socket"
#public vars
channel = Channel(String).new
csocket = Socket.tcp(Socket::Family::INET)
socket_conn=false
puts "Welcome:"
spawn do
server = TCPServer.new("0.0.0.0", 9090)
loop do #handle tcp client reconnects - do forever
socket = server.accept
csocket = socket.dup
socket_conn=true
p! socket_conn
print "\r"
while line = socket.gets
channel.send(line)
end
socket_conn=false
p! socket_conn
print "\r"
end
end
spawn do #handle stdin input char by char - do until ctrl-c pressed
while (char = STDIN.raw &.read_char) != '\u{3}' #ctrl-c
channel.send(char.to_s)
end
channel.send('\u{3}'.to_s)
end
loop do #do until cttrl-c
r = channel.receive
if r == "\u0003" #handle ctrl-c from channel
break
end
p! socket_conn
print "\r"
p! r
print "\r"
if socket_conn
csocket.puts "got: #{r}"
end
puts "got: #{r}"
print "\r"
end