45

I'm trying to run a minecraft server on my unRAID server.

The server will run in the shell, and then sit there waiting for input. To stop it, I need to type 'stop' and press enter, and then it'll save the world and gracefully exit, and I'm back in the shell. That all works if I run it via telnetting into the NAS box, but I want to run it directly on the box.

this is what I previously had as a first attempt:

#define USER_SCRIPT_LABEL Start Minecraft server
#define USER_SCRIPT_DESCR Start minecraft server. needs sde2 mounted first
cd /mnt/disk/sde2/MCunraid
screen -d -m -S minecraft /usr/lib/java/bin/java -Xincgc -Xmx1024M -jar CraftBukkit.jar

MCunraid is the folder where I have the Craftbukkit.jar and all the world files etc. If I type that screen line in directly, the screen does setup detached and the server launches. If I execute that line from within the script it doesn't seem to set up a screen

for stopping the server, I need to 'type' in STOP and then press enter. My approach was

screen -S minecraft -X stuff "stop $(echo -ne '\r')"

to send to screen 'minecraft' the text s-t-o-p and a carriage return. But that doesn't work, even if I type it directly onto the command line. But if I 'screen -r' I can get to the screen with the server running, then type 'stop' and it shuts down properly.

The server runs well if I telnet in and do it manually, just need to run it without being connected from my remote computer.

  • This looks right. What's the full content of the script and how are you running it? Does it produce any output? How do you tell that screen failed to start? Try adding set -x at the top of the script (just after the #! line) and report the trace output when you run the script. – Gilles 'SO- stop being evil' May 28 '11 at 13:05
  • that is the full content of the script :) the screen command works if I type it in directly, so I think my main issue is the stop part – richard plumb May 28 '11 at 13:23
  • You wrote “If I execute that line from within the script it doesn't seem to set up a screen”. So does the start part work or not? If it doesn't, see my first comment. – Gilles 'SO- stop being evil' May 28 '11 at 13:53
  • I'm trying to run it as an unMENU user script. If I have the user script with that exact screen command, nothing happens. If I type the screen command into a telnet window, it launches the server in a screen like you'd expect. So I think there is some difference I don't understand in the way unMENU user scripts are handled. – richard plumb May 28 '11 at 14:02
  • Now we're getting somewhere. Please update your question with information on how you're using unMENU. And do try adding two lines #!/bin/bash and set -x at the top of the script, and show us the trace output from the script. You might need to look in the unMENU documentation to find out where that output goes. – Gilles 'SO- stop being evil' May 28 '11 at 14:05
41

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.

  • 1
    beautiful, works great (at least from the command line, will poke the unmenu guys later). This seems to have thrown quite a few people and its the first time I've seen a concrete solution. I just wish I had enough points to vote you up :D – richard plumb May 28 '11 at 15:11
  • Damn s**t ! It works even screen is already attached, without reattaching it ! What's a great way to send commands to simple apps from other apps in system. Thanks! :) – Grzegorz Wierzowiecki Nov 29 '11 at 9:54
  • I never had this problem, probably because I always planned to have several (named) windows in my screen session, and I always choose window by name. – Ekevoo Jan 8 '14 at 13:48
  • Manual, for reference: -X Send the specified command to a running screen session. You may use the -S option to specify the screen session if you have several screen sessions running. You can use the -d or -r option to tell screen to look only for attached or detached screen sessions. Note that this command doesn't work if the session is password protected. – KrisWebDev Sep 24 '16 at 8:41
  • 3
    this doesn't work for me. I have created a screen with screen -d -m -S hi and then run screen -S hi -p 0 -X stuff "cd <some_directory>^M" and get nothing as a result... it just sends "cd <some_directory>^M" as a string and doesn't interpret "^M" as enter key... – Tanner Strunk Jun 10 '18 at 5:44
23

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"
  • if I manually switch over using screen -r, I can see the screen, and there is no text entered at all. even if the carriage return was failing, I should still get 'stop' typed in. But nothing – richard plumb May 28 '11 at 13:24
  • if I have a script with screen -r on one line, and then screen -X stuff "stop^M" then it does stop the server, but also complains with 'error uknown option r' – richard plumb May 28 '11 at 13:36
  • I tested in here by creating screen session, then using the command above and it works perfectly. Are you able to connect to your screen session using screen -d -RR minecraft? – Caleb May 28 '11 at 13:38
  • yes, that connects me to the screen. so does screen -r.. hang on, if I try screen -S minecraft -X stuff "stop^M" then manually screen -r, there is 'stop' text in the screen. – richard plumb May 28 '11 at 13:39
  • Works for me. Perhaps you have something funky in your .screenrc or you have a bunch of defunkt screen sessions open with that name and so you are sending data to the wrong one? screen -list? – Caleb May 28 '11 at 13:42
5

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!"
  • Nice and Concise... Welcome to U&L – eyoung100 Dec 26 '14 at 16:50

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.