tty-command
tty-command copied to clipboard
Can't run shells in interactive mode
Describe the problem
Shells cannot be run with TTY::Command. Keyboard input is not read by the shell.
Steps to reproduce the problem
require 'tty-command'
cmd = TTY::Command.new(pty: true, printer: :quiet)
cmd.run(*ARGV)
Actual behaviour
(slightly edited to remove identifying information)
% bundle exec ruby ./test.rb dash
$ ls
oh no input is going nowhere
^C
$ ^C
$ but ctrl-c is handled?
^C
$ ctrl-d does nothing
^C
$ ^C
$ ^C
$ i have to kill this from another shell
zsh: terminated bundle exec ruby ./test.rb
% bundle exec ruby ./test.rb bash
bash: cannot set terminal process group (84144): Inappropriate ioctl for device
bash: no job control in this shell
$ input does not go to the shell
ctrl c kills the process
^CTraceback (most recent call last):
5: from ./test.rb:6:in `<main>'
4: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command.rb:104:in `run'
3: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command.rb:185:in `execute_command'
2: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command/process_runner.rb:48:in `run!'
1: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command/process_runner.rb:146:in `read_streams'
./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command/process_runner.rb:146:in `join': Interrupt
bundle exec ruby ./test.rb zsh
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
zsh: substitution failed
ls
I can't even get a prompt on zsh
^CTraceback (most recent call last):
5: from ./test.rb:6:in `<main>'
4: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command.rb:104:in `run'
3: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command.rb:185:in `execute_command'
2: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command/process_runner.rb:48:in `run!'
1: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command/process_runner.rb:146:in `read_streams'
./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command/process_runner.rb:146:in `join': Interrupt
% bundle exec ruby ./test.rb ssh $some_host
<snip MOTD banner>
$ ls
^CTraceback (most recent call last):
5: from ./test.rb:6:in `<main>'
4: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command.rb:104:in `run'
3: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command.rb:185:in `execute_command'
2: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command/process_runner.rb:48:in `run!'
1: from ./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command/process_runner.rb:146:in `read_streams'
./.bundle/gems/ruby/2.6.0/gems/tty-command-0.9.0/lib/tty/command/process_runner.rb:146:in `join': Interrupt
Expected behaviour
A working interactive shell.
Describe your environment
- OS version: Debian linux sid
- Ruby version: 2.6.6 and 2.7.1
- TTY::Command version: 0.9.0
Hi Felipe 👋
Thanks for rasing the issue and using tty-command
.
Would you have time to investigate potential fix?
It looks like the issue is that ProcessRunner
only tries to write to stdin
once when the command is started: https://github.com/piotrmurach/tty-command/blob/da308658f0cb96db78d5b3b25985fae0434973a0/lib/tty/command/process_runner.rb#L46
I think to be able to wrap interactive commands, we would need another thread to manage stdin.
I was able to use https://github.com/stripe/subprocess to wrap an interactive command.
@ryansch - mind providing a code snippet to show how you used subprocess to solve this?
@codefriar I'd like this to be fixed in the tty-command
project. I maintain many Ruby projects and have limited time. Thus I need help and encourage any contributions that get us closer to resolving this problem. Unfortunately, your comment doesn't get us in this direction. This is not the place to seek explanations on how to use other libraries and I suggest you open an issue in the other project.
@piotrmurach My apologies. My initial read of @ryansch 's comment was that he'd gotten this to work in tty-command perhaps by utilizing the subprocess command. I was hoping to prompt him to share his fix for tty-command.
Hi all, is this possible now? When I run a shell in a subprocess with pty: true (for example kubectl to open a shell in a pod in Kubernetes), the shell starts and I can press keys etc but when I press enter nothing happens in the shell. Any suggestion? Thanks!
I just wrote https://github.com/outstand/dash/blob/cd7c740afd1dc7fa809afd630e8a50ee68e391ca/lib/state.rb#L65 to integrate Subprocess
a bit more with this gem. At least this way I get similar logging output!
@codefriar I finally did... ^
I looked at the differences between tty-command
and subprocess
and I think subprocess
works here because it gives the caller the ability to directly connect the spawned process to STDIN, STDOUT, STDERR.
@ryansch Do you have any suggestions on helping tackle this issue in tty-command
itself? I'm all for exposing streams to connect directly. This is important to solve. Any help would be really appreciated!
I had originally thought about grafting subprocess into this gem but I think exposing the streams might be all we need. I'll see if I can't work up an experiment to test it.