Can I send some text to the STDIN of an active process running in a screen session?

This answer doesn't solve the problem, but it's left here because 30+ people found it useful, otherwise I would have deleted it long time ago.

Write to /proc/*pid of the program*/fd/0. The fd subdirectory contains the descriptors of all the opened files and file descriptor 0 is the standard input (1 is stdout and 2 is stderr).

You can use this to output messages on the tty where a program is running, though it does not allow you to write to the program itself.

Example

Terminal 1:

[ciupicri@hermes ~]$ cat
shows on the tty but bypasses cat

Terminal 2:

[ciupicri@hermes ~]$ pidof cat
7417
[ciupicri@hermes ~]$ echo "shows on the tty but bypasses cat" > /proc/7417/fd/0

Screen based solution

Start the server like this:

# screen -d -m -S ServerFault tr a-z A-Z # replace with your server

screen will start in detached mode, so if you want to see what's going on, run:

# screen -r ServerFault

Control the server like this:

# screen -S ServerFault -p 0 -X stuff "stop^M"
# screen -S ServerFault -p 0 -X stuff "start^M"
# screen -S ServerFault -p 0 -X stuff "^D" # send EOF

(this answer is based on sending text input to a detached screen from the Unix & Linux sibling site)

Explanation of the parameters:

-d -m
  Start screen in detached mode. This creates a new session but doesn’t attach to it. This is useful for system startup scripts.

-S sessionname
  Set the name of the new session to sessionname.

-r [pid.tty.host]
-r sessionowner/[pid.tty.host]
  Resume a detached screen session.

-p number_or_name|-|=|+
  Preselect a window. This is useful when you want to reattach to a specific window or you want to send a command via the -X option to a specific window.

-X
  Send the specified command to a running screen session e.g. stuff.

stuff [string]
  Stuff the string string in the input buffer of the current window. This is like the paste command but with much less overhead. Without a parameter, screen will prompt for a string to stuff. You cannot paste large buffers with the stuff command.

tmux based solution

Start the server like this:

# tmux new-session -d -s ServerFault 'tr a-z A-Z' # replace with your server

tmux will start in detached mode, so if you want to see what's going on, run:

# tmux attach-session -t ServerFault

Control the server like this:

# tmux send-keys -t ServerFault -l stop
# tmux send-keys -t ServerFault Enter
# tmux send-keys -t ServerFault -l start
# tmux send-keys -t ServerFault Enter
# tmux send-keys -t ServerFault C-d # send EOF

Explanation of the parameters:

new-session [-AdDEPX] [-c start-directory] [-e environment] [-f flags] [-F format] [-n window-name] [-s session-name] [-t group-name] [-x width] [-y height] [shell-command]
(alias: new)
  Create a new session with name session-name.
  The new session is attached to the current terminal unless -d is given. window-name and shell-command are the name of and shell command to execute in the initial window.

send-keys [-FHlMRX] [-N repeat-count] [-t target-pane] key
(alias: send)
  Send a key or keys to a window. Each argument key is the name of the key (such as 'C-a' or 'NPage') to send; if the string is not recognised as a key, it is sent as a series of characters. All arguments are sent sequentially from first to last.
  The -l flag disables key name lookup and processes the keys as literal UTF-8 characters. The -H flag expects each key to be a hexadecimal number for an ASCII character.


It is possible to send input text to a running process without running the screen utility, or any other fancy utility. And it can be done by sending this input text to the process' standard input "file" /proc/PID#/fd/0.

However, the input text needs to be sent in a special way to be read by the process. Sending the input text via the regular file write method will not cause the process to receive the text. This is because doing so will only append to that "file", but will not trigger the process to read the bytes.

To trigger the process to read the bytes, it is necessary to do an IOCTL operation of type TIOCSTI for every single byte to be sent. This will place the byte into the process' standard input queue.

This is discussed here with some examples in C, Perl, and Python:

https://unix.stackexchange.com/questions/48103/construct-a-command-by-putting-a-string-into-a-tty/48221

--

So to answer the original question asked almost 9 years ago, the cron job would need to run some small utility script / program similar to the examples people wrote for that other question, which would send the string "stop\n" to that server process in the question, by sending each of the 5 bytes via an IOCTL operation of type TIOCSTI.

Of course this will only work on systems that support the TIOCSTI IOCTL operation type (like Linux), and only from the root user account, as these "files" under /proc/ are "owned" by root.


Try this to start:

# screen
# cd /path/to/wd
# mkfifo cmd
# my_cmd <cmd
C-A d

And this to kill:

# cd /path/to/wd
# echo "stop" > cmd
# rm cmd