You are not logged in.

#1 2017-07-12 02:13:53

aussieevil
Member
Registered: 2014-06-19
Posts: 25

Sending a string to an already running process

I'm making a series of shell scripts that simplifies the Minecraft server admin tools, and I'm wondering how do I send a process that's already running under screen input like it was typed in on stdin in the process?

Offline

#2 2017-07-12 06:42:54

Xyne
Administrator/PM
Registered: 2008-08-03
Posts: 6,963
Website

Re: Sending a string to an already running process

aussieevil wrote:

like it was typed in on stdin in the process?

Do you mean "piped in on stdin" or "typed in"?

You can use xdotool to select the window and simulate keystrokes ("typed in").

"piped in on stdin" is trickier. You could use a FIFO, but the running process is blocked until input arrives and the FIFO is normally closed after another process writes to it. Read the discussion here.

Out of curiosity, I came up with workaround, even though I expect that you are looking for the other solution. The following script will open a command, connect to the command's STDIN, and repeatedly read the contents from a FIFO to pipe into the command:

#!/usr/bin/env python3

import os.path
import stat
import subprocess
import sys

if not sys.argv[2:]:
  sys.exit('usage: {} <fifo name> <cmd> [<cmd args>...]'.format(os.path.basename(sys.argv[0])))

fifo = sys.argv[1]
cmd = sys.argv[2:]

try:
  os.mkfifo(fifo)
except FileExistsError:
  if not stat.S_ISFIFO(os.stat(fifo).st_mode):
    sys.exit('{} is not a FIFO'.format(fifo))

with subprocess.Popen(cmd, stdin=subprocess.PIPE) as p:
  while True:
     with open(fifo, 'rb') as f:
      p.stdin.write(f.read())
      p.stdin.flush()

Save it as e.g. fifowrapper and make it executable. The first argument is a FIFO path (which it will create if necessary). All other arguments are interpreted as the command to run. Example usage:

$ fifowrapper /path/to/myfifo mycommand myarg1 myarg2 myarg3[/*]
$ echo "first line of input" > /path/to/myfifo[/*]
$ echo "second line of input" > path/to/myfifo[/*]

Because of the infinite loop, you'll need to kill it with ctrl+c, but you would easily add a condition to stop the loop on certain input, e.g.

data = f.read()
if data == b'die':
  break
else:
  p.stdin.write(data)
  p.stdin.flush()

If the command is running on a remote server, you will need to use ssh or sshfs to pipe the data in.


My Arch Linux StuffForum EtiquetteCommunity Ethos - Arch is not for everyone

Offline

#3 2017-07-12 10:18:38

Trilby
Inspector Parrot
Registered: 2011-11-29
Posts: 29,523
Website

Re: Sending a string to an already running process

In addition to the above clarification of whether you need to simulate typing or not, can the input be known before the process starts, or would there at least be an agorithm by which the input is defined dynamically by the response of the programs output?

In any case where there is not a X11 terminal emulator instatiation of your screen session, I'd disagree with Xyne: sending information to an input pipe is much easier than simulating typing - other than xdotool or comparable tools there is no way to send "typed" input (and these tools require an X11 emulator running the screen session with the appropriate screen pane having input focus).  There are countless ways to send input to the stdin of a process though, including a pipe when the process starts, an expect script, a socket for two way interaction, etc.

What exactly do you need to do?


"UNIX is simple and coherent..." - Dennis Ritchie, "GNU's Not UNIX" -  Richard Stallman

Offline

#4 2017-07-12 12:16:02

Xyne
Administrator/PM
Registered: 2008-08-03
Posts: 6,963
Website

Re: Sending a string to an already running process

Trilby wrote:

I'd disagree with Xyne: sending information to an input pipe is much easier than simulating typing

I did indeed assume that the screen session is running in an X11 terminal emulator.  I also understood that in the case of stdin, the program needs to keep processing input from the pipe while separate programs write to it. If the input can be piped in from a single process then that is the better solution, but if that information is available at the beginning there should be no need to interact with the running process after launch.

Trilby wrote:

What exactly do you need to do?

This is the real question.


My Arch Linux StuffForum EtiquetteCommunity Ethos - Arch is not for everyone

Offline

Board footer

Powered by FluxBB