0

Lets say I have top or some ncurses program running in a graphical terminal, and from outside this terminal I'd like to execute a command, that would replace top with another program of my choosing.

I imagine there to be a generic approach to this, something that

  • finds the PTY for the correct window
  • kills the program in the terminal, while keeping the PTY
  • Spawns the replacement command, and
  • hooks up PTY I/O to read/write to/from the command

My googling for preexisting generic solutions to wrap this has not yielded useful pointers.

The specific use-case I have for this: I want to switch the tmux client running in gnome-terminal from one /tmp/tmux-$UID/Socket (=server) to another one belonging to the same user, without "losing" the window.

I'm looking for the generic solution, because I could not get a connected tmux-client to connect/attach to a new socket at run-time.

2 Answers 2

1

To my knowledge there is no generic solution to do this. The tmux client is running in a pty which belongs to gnome-terminal, you can't change the pty gnome-terminal is talking to or change the program the pty belongs to (either the master or slave end) without gnome-terminal's participation or without some seriously fiddly code (for example, see reptyr, which does the reverse of what you want - moving a program to a different pty rather than a pty to a different program).

For tmux specifically, if your tmux is new enough (2.4 or later) you can use detach-client -E to replace the running tmux client with a different process - this could be another tmux client, for example:

tmux -Lfirstsocket detach -E 'tmux -Lsecondsocket attach'

If your tmux is not new enough, your options are probably limited to:

  • open a new tab in gnome-terminal with the new tmux client and close the original tab;

  • close your gnome-terminal entirely and open another one with the program you want;

  • open the new tmux inside the old tmux and then hide the status line and unset the prefix in the old tmux, so it is still running but won't get in the way.

1
  • Thank you for this answer (and for tmux itself)! The -E option for detach-client was the missing piece I did not know about. I had looked for an execcommand, or an option to run-shell, and hadn't re-read the manpage recently enough. Debian Buster has a new enough version, so I can use that. I was aware of screenify+reptyr, and reasoned like you in your first paragraph. Thanks for confirming the hunch about the generic case, and for having added -E to detach-client, which solves my specific need! Feb 16, 2020 at 19:52
1

The problem with terminal emulators is that they will close, when the executable they spawned exits. But you can run a little wrapper inside the terminal emulator that will:

  1. Receive a command from a UNIX socket,
  2. Execute it,
  3. Kill the command when a new message arrives.
  4. Go to 1.

Something like this little gist. You save the files in a directory, can compile the server with:

gcc -Wall -o server libwrapper.c server.c

and the client with:

gcc -Wall -o client libwrapper.c client.c

You run the server in one terminal:

./server

and switch commands through the client in another one:

./client /bin/cat /etc/motd
2
  • +1 Thanks for taking the workaround from thought experiment to implementation :) Feb 16, 2020 at 21:32
  • Its more like a stub implementation: it almost doesn't deal with any error conditions. Feb 16, 2020 at 21:42

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.