sending text input to a detached screen

I can solve at least part of the problem: why the stop part isn't working. Experimentally, when you start a Screen session in detached mode (screen -d -m), no window is selected, so input later sent with screen -X stuff is just lost. You need to explicitly specify that you want to send the keystrokes to window 0 (-p 0). This is a good idea anyway, in case you happen to create other windows in that Screen session for whatever reason.

screen -S minecraft -p 0 -X stuff "stop^M"

(Screen translate ^M to control-M which is the character sent by the Enter key.)

The problem with starting the session from a script is likely related to unMENU.


First, a note on easily entering newlines:

Just a heads up that the $() construct strips newlines from the output of command so that the output lines can be used as the arguments for other programs. This can cause unexpected behavior. In this case I assume you are specifically trying to send the equivalent of Enter keystroke. While the carriage return you are sending with \r won't get striped, there are several easier ways to enter that character without the need for the extra command.

  1. You can place a regular newline inside your double quotes

    screen -S minecraft -X stuff "stop
    "
    
  2. Or you can enter the character in a terminal line using the Ctrl+v Enter sequence. This will look something like ^M in the terminal, but it's a special newline character.

    screen -S minecraft -X stuff "stop^M"
    

Secondly, A note on erratic screen behavior. (Explanation and solution by Gilles)

Screen has an issue with accepting input to a screen session that has never been attached. If you run this it will have failed:

screen -d -m -S minecraft zsh
screen -S minecraft -X stuff "stop^M"
screen -r minecraft

But if you run this it will work:

screen -d -m -S minecraft zsh
screen -r minecraft (then disconnect with Ctrl-a-d)
screen -S minecraft -X stuff "stop^M"
screen -r minecraft

Lastly, you could use the much better behaved tmux instead of screen.

GNU-Screen has been a de-facto terminal multiplexer for many years, but it has long ceased to be developed and bugs and quirks aren't getting fixed. Tmux is under active development, includes many features that screen can't touch, and its behavior out of the box is rather more intuitive. Also, it's better documented. Here's how you would convert your code:

# Start new detached tmux session with a named window pane running the java app
tmux new-session -d -n minecraft /usr/lib/java/bin/java [args]

# Send it keys to stop the mincraft server
tmux send-keys -t minecraft "stop^M"

I apologize for digging up this old post, but this would have helped me in my endeavors had this information been available at the time I had a similar issue. There are many questions about how to send screen commands in a bash script. As with cat skinning this may be done, but I like this way. With this you can send any command or say anything just by calling the say_this function.

#!/bin/bash

say_this()
{
    screen -S minecraft -p 0 -X stuff "$1^M"
}

say_this "say Saving world"
say_this "save-off"
say_this "save-all"
...

This is with ssh!

#!/bin/bash

say_this()
{
    # Dont forget to set NAME or whatever
    ssh -p 8989 192.168.1.101 screen -S $NAME -p 0 -X stuff \"$1^M\"
}

say_this "say test"
say_this "say !@#$%^&*()<>?This string will work!"