sshクライアントみたいなプログラムをどうやったらつくれるのか知りたかったので、とりあえずローカルでforkしたプロセスをラップするだけのプログラムをつくってみた。
Python版
PTYの扱いがいまいちわからなかったので、PtyProcessというライブラリを使ってずるをした。
import sys
import tty
import os
import termios
import select
import ptyprocess
import threading
import time
stop_event = threading.Event()
def read_stdin(p):
while not stop_event.is_set():
r, w, e = select.select([sys.stdin], [], [], 0)
#print('hoge')
if sys.stdin in r:
x = sys.stdin.read(1)
p.write(x)
time.sleep(0.01)
#args = ['python']
args = ['bash']
p = ptyprocess.PtyProcessUnicode.spawn(args)
t = threading.Thread(target=read_stdin, args=(p,))
t.start()
oldtty = termios.tcgetattr(sys.stdin)
tty.setraw(sys.stdin.fileno())
print("raw mode started")
tty.setcbreak(sys.stdin.fileno())
print("cbreak mode started")
while True:
try:
x = p.read(1)
sys.stdout.write(x)
sys.stdout.flush()
except EOFError:
print("subprocess exit")
break
stop_event.set()
t.join()
termios.tcsetattr(sys.stdin, termios.TCSADRAIN, oldtty)
http://www.betatechnology.jp/pp/index.php?Unix%2F%E7%AB%AF%E6%9C%AB
http://docs.python.jp/3/library/pty.html
http://docs.python.jp/3.5/library/termios.html
http://docs.python.jp/3.5/library/tty.html
Ruby版
rubyでもやってみた
require "pty"
require "termios"
STDIN.extend Termios
term_preset = STDIN.tcgetattr
system("stty raw -echo")
begin
PTY.spawn("bash -i") do |pin, pout|
Thread.new do
loop do
pout.print STDIN.getc.chr
end
end
loop do
print pin.sysread(512)
STDOUT.flush
end
end
rescue EOFError => e
STDIN.tcsetattr(Termios::TCSANOW, term_preset)
end
termiosはgem install ruby-termios
でインストールできる。
http://stackoverflow.com/questions/2730642/wrapper-around-bash-control-stdin-and-stdout
http://melborne.github.io/2013/02/19/flippy-console-now-added/