# [Unix-Shell] Bash-Problem: Wait: PID



## MoD2Cody (24. Februar 2014)

Hallo Zusammen!

Ich bin neu in diesem Forum und habe sogleich ein Problem, welches auf eine baldige Lösung hofft. 

Zu allererst möchte ich klar stellen, es geht um ein Minecraft-Server-Startskript, wenn das eine Rolle spielt.
Jedenfalls habe ich eine while-loop eingebaut, damit, falls der Server gestoppt wird nach 'ner kurzen Zeit auch wieder automatisch startet. Dazu will ich den Server in einem Screen starten, damit ich selbst wenn PuttY mal ausfällt später wieder darauf zugreifen kann. Hier ist nun das erste Problem wenn ich jetzt hypothetisch gesehen, das in mein Skript reinschreiben:


```
#!/bin/bash
               cd "/home/minecraft"
               while true; do
                   sleep 3
                   echo "*** Das Starten des Minecraft-Servers beginnt!"
                   echo "*** Starte MoD-Craft mit dem Screen 'craftbukkit'"
                  screen -L -A -m -d -S craftbukkit  java -Xmx6144M -Xms4096M -jar /home/minecraft/craftbukkit.jar nogui
                  echo "*** Du kannst nun mit screen -r craftbukkit, bzw. screen -x craftbukkit zur Console connecten"
               done
```

Würde das Skript sofort wieder von vorne Anfangen, da nicht abgewartet wird, bis der Screen Prozess terminiert wurde.
Dazu habe ich mich erkundigt und folgenden Befehl in Betracht gezogen: 


```
#!/bin/bash
               pid=`pidof java`
               cd "/home/minecraft"
               while true; do
                   sleep 3
                   echo "*** Das Starten des Minecraft-Servers beginnt!"
                   echo "*** Starte MoD-Craft mit dem Screen 'craftbukkit'"
                   screen -L -A -m -d -S craftbukkit  java -Xmx6144M -Xms4096M -jar /home/minecraft/craftbukkit.jar nogui
                   echo "*** Du kannst nun mit screen -r craftbukkit, bzw. screen -x craftbukkit zur Console connecten"
                   wait $pid &
               done
```

Da dadurch aber ein Child von der Shell beansprucht, versuchte ich mein Glück mit einer Schleife.


```
#!/bin/bash
               pid=`pidof java`
               cd "/home/minecraft"
               while true; do
                   sleep 3
                   echo "*** Das Starten des Minecraft-Servers beginnt!"
                   echo "*** Starte MoD-Craft mit dem Screen 'craftbukkit'"
                   screen -L -A -m -d -S craftbukkit  java -Xmx6144M -Xms4096M -jar /home/minecraft/craftbukkit.jar nogui
                   echo "*** Du kannst nun mit screen -r craftbukkit, bzw. screen -x craftbukkit zur Console connecten"
                   while [[ $pid{?} == 0 ]]; do
                       sleep 3
                       echo "Server wird neugestartet."
               done
```

Dadurch, dass solange überprüft wird, bis der Prozess terminiert wurde (==0) sollte es eig. funktionieren, tut es jedoch nicht.

P.S. : Ich bin mir bewusst, dass ich mich ziemlich schlecht hiermit auskenne, aber jeder hat mal klein angefangen. Kritik ist erwünscht.

Ich wäre sehr dankbar über produktiven Antworten, ich bedanke mich schonmal im Vorraus
MoD2Cody


----------



## Bratkartoffel (25. Februar 2014)

Hi,

habe meinen Minecraft Server mit einem Init-Script zuerst mal in den Autostart eingetragen. Die Checks, ob er noch läuft, hatte ich erst im Crontab eingetragen, inzwischen hab ichs dort aber wieder entfernt, da er eh rock-solid läuft.

Hier mal das Init-Script: /etc/init.d/minecraft

```
#!/bin/bash
# /etc/init.d/minecraft
# version 0.3.6 2011-10-17 (YYYY-MM-DD)

### BEGIN INIT INFO
# Provides:   minecraft
# Required-Start: $local_fs $remote_fs
# Required-Stop:  $local_fs $remote_fs
# Should-Start:   $network
# Should-Stop:    $network
# Default-Start:  2 3 4 5
# Default-Stop:   0 1 6
# Short-Description:    Minecraft server
# Description:    Starts the minecraft server
### END INIT INFO

#Settings
SERVICE='minecraft_server.jar'
OPTIONS='nogui'
USERNAME='minecraft'
WORLD='world'
MCPATH='/home/minecraft/'
BACKUPPATH='/home/minecraft/backups'
CPU_COUNT=2
INVOCATION="java -Xmx1024M -Xms1024M -XX:+UseConcMarkSweepGC -XX:+CMSIncrementalPacing -XX:ParallelGCThreads=$CPU_COUNT -XX:+AggressiveOpts -jar $SERVICE $OPTIONS"

ME=`whoami`
as_user() {
  if [ $ME == $USERNAME ] ; then
    bash -c "$1"
  else
    su - $USERNAME -c "$1"
  fi
}

mc_start() {
  if  pgrep -u $USERNAME -f $SERVICE > /dev/null
  then
    echo "$SERVICE is already running!"
  else
    echo "Starting $SERVICE..."
    cd $MCPATH
    as_user "cd $MCPATH && screen -dmS minecraft $INVOCATION"
    sleep 5
    if pgrep -u $USERNAME -f $SERVICE > /dev/null
    then
      echo "$SERVICE is now running."
    else
      echo "Error! Could not start $SERVICE!"
    fi
  fi
}

mc_saveoff() {
  if pgrep -u $USERNAME -f $SERVICE > /dev/null
  then
    echo "$SERVICE is running... suspending saves"
    as_user "screen -p 0 -S minecraft -X eval 'stuff \"say SERVER BACKUP STARTING. Server going readonly...\"\015'"
    as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-off\"\015'"
    as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-all\"\015'"
    sync
    sleep 5
  else
    echo "$SERVICE is not running. Not suspending saves."
  fi
}

mc_saveon() {
  if pgrep -u $USERNAME -f $SERVICE > /dev/null
  then
    echo "$SERVICE is running... re-enabling saves"
    as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-on\"\015'"
    as_user "screen -p 0 -S minecraft -X eval 'stuff \"say SERVER BACKUP ENDED. Server going read-write...\"\015'"
  else
    echo "$SERVICE is not running. Not resuming saves."
  fi
}

mc_stop() {
  if pgrep -u $USERNAME -f $SERVICE > /dev/null
  then
    echo "Stopping $SERVICE"
    as_user "screen -p 0 -S minecraft -X eval 'stuff \"say SERVER SHUTTING DOWN IN 10 SECONDS. Saving map...\"\015'"
    as_user "screen -p 0 -S minecraft -X eval 'stuff \"save-all\"\015'"
    sleep 5
    as_user "screen -p 0 -S minecraft -X eval 'stuff \"stop\"\015'"
    sleep 5
  else
    echo "$SERVICE was not running."
  fi
  if pgrep -u $USERNAME -f $SERVICE > /dev/null
  then
    echo "Error! $SERVICE could not be stopped."
  else
    echo "$SERVICE is stopped."
  fi
}

mc_update() {
  if pgrep -u $USERNAME -f $SERVICE > /dev/null
  then
    echo "$SERVICE is running! Will not start update."
  else
    MC_SERVER_URL=http://s3.amazonaws.com/MinecraftDownload/launcher/minecraft_server.jar?v=`date | sed "s/[^a-zA-Z0-9]/_/g"`
    as_user "cd $MCPATH && wget -q -O $MCPATH/minecraft_server.jar.update $MC_SERVER_URL"
    if [ -f $MCPATH/minecraft_server.jar.update ]
    then
      if `diff $MCPATH/$SERVICE $MCPATH/minecraft_server.jar.update >/dev/null`
      then
        echo "You are already running the latest version of $SERVICE."
      else
        as_user "mv $MCPATH/minecraft_server.jar.update $MCPATH/$SERVICE"
        echo "Minecraft successfully updated."
      fi
    else
      echo "Minecraft update could not be downloaded."
    fi
  fi
}

mc_backup() {
   DATE=`date "+%Y-%m-%d_%H-%M"`
   echo "Backing up minecraft world..."

         if [ -d $BACKUPPATH/$DATE ]; then
                 echo "Backup $DATE allready exists!" >&2
                 return
         fi

         mkdir $BACKUPPATH/$DATE
         pushd $MCPATH 2>&1 >/dev/null
     tar -czf $BACKUPPATH/$DATE/$WORLD.tgz $WORLD
     cp $SERVICE $BACKUPPATH/$DATE
   popd 2>&1 >/dev/null

   echo "Backup complete"
}

mc_command() {
  command="$1";
  if pgrep -u $USERNAME -f $SERVICE > /dev/null
  then
    pre_log_len=`wc -l "$MCPATH/server.log" | awk '{print $1}'`
    echo "$SERVICE is running... executing command"
    as_user "screen -p 0 -S minecraft -X eval 'stuff \"$command\"\015'"
    sleep .1 # assumes that the command will run and print to the log file in less than .1 seconds
    # print output
    tail -n $[`wc -l "$MCPATH/server.log" | awk '{print $1}'`-$pre_log_len] "$MCPATH/server.log"
  fi
}

#Start-Stop here
case "$1" in
  start)
    mc_start
    ;;
  stop)
    mc_stop
    ;;
  restart)
    mc_stop
    mc_start
    ;;
  update)
    mc_stop
    mc_backup
    mc_update
    mc_start
    ;;
  backup)
    mc_saveoff
    mc_backup
    mc_saveon
    ;;
  status)
    if pgrep -u $USERNAME -f $SERVICE > /dev/null
    then
      echo "$SERVICE is running."
    else
      echo "$SERVICE is not running."
    fi
    ;;
  command)
    if [ $# -gt 1 ]; then
      shift
      mc_command "$*"
    else
      echo "Must specify server command (try 'help'?)"
    fi
    ;;

  *)
  echo "Usage: /etc/init.d/minecraft {start|stop|update|backup|status|restart|command \"server command\"}"
  exit 1
  ;;
esac

exit 0
```
Bei dir müsstet du wahrscheinlich erstmal die Settings im Script anpassen dasses läuft.

Grüße,
BK


----------



## MoD2Cody (25. Februar 2014)

Zuerst möchte ich sehr herzlich danken, für deine Mühe.

Dein Skript ist sehr umfassend und könnte ich so kopieren, ohne großartige Änderungen vorzunehmen. Allerdings bin ich immer noch an der Schleife interessiert, da ich möchte, dass, selbst wenn ich im Spiel den /stop Befehl eingebe, den Server wieder neustarte. (Besonders wichtig, wenn ich mal nicht da bin, und ein Freund die Sache klären soll, denn dann hat er keinen Zugriff auf die Konsole)

Oder gäbe es eine andere Möglichkeit, dies zu erfüllen, vllt. ein Skript, dass immer läuft und darauf aufpasst, dass der Server immer läuft, falls nicht startet es ihn dann, wäre soetwas möglich? 

Auf jeden Fall bräuchte ich wenn das o. g. nicht zutrifft eine Hilfe zu der While $pid Sache.
Wait ist ausgeschlossen, aber wieso funktioniert das Skript, so wie ich es geschrieben habe nicht?
Wäre sehr hilfreich das zu wissen.

Liebe Grüße
MoD2Cody


----------



## Bratkartoffel (26. Februar 2014)

Hi MoD2Cody,

das Script würde ich so lassen, mit dem kannst du das ganze schnell starten / stoppen / neustarten und entspricht so auch dem Linux-Standard. Init-Script sind genau hierfür da, zur Steuerung von Diensten.

Ich hab dir eh etwas nebenläufig den Tip mit Cron gegeben. Den kannst du vergleichen mit dem Taskplaner von Windows. Zu bestimmten Zeiten wird ein Script ausgeführt. Dieses kannst du zum Beispiel alle 10 Minuten machen, genaue Syntax und Beispiele findest du in der /etc/crontab oder über "man 5 crontab".

Du erstellst also jetzt quasi ein neues Script. Dieses ruft das obige Init-Script einmal mit dem Paramter "status" auf. Der Rückgabecode ($?) ist für dich dann weiter relevant. Je nachdem kannst du in dem Script dann per If-Abfrage das Ding neustarten.

Das Script #2 kannst du jetzt in die crontab übernehmen und alle 5 Minuten durchlaufen lassen.

Grüße,
BK


----------



## MoD2Cody (26. Februar 2014)

Dank dir, werde mich gleich mal dransetzen. 

Gruß
Cody


----------



## MoD2Cody (27. Februar 2014)

So hat alles wunderbar geklappt, jedoch besteht nun ein neues Problem, welches hoffentlich schnell gelöst werden kann.

Auf jeden Fall bin ich dir sehr dankbar, hab alles so befolgt, wie beschrieben und das Ergebnis wurde auch erzielt. 

Nun habe ich mein Skript allerdings um ein wenig erweitert und habe ein CASE reingesetzt. Nun ist es aber so, dass ich nicht weiß, wie ich den Pfad zum Befehl "home/minecraft/skript.sh start" in den Cronjob eintrage. "exec "home/minecraft/skript.sh start"" funktioniert jedenfalls nicht, und viel Erfahrung hab ich damit auch noch nicht.

Wäre sehr dankbar für jegliche Antworten

Gruß
Cody


----------



## Bratkartoffel (28. Februar 2014)

Hi,

ich glaube, du hast im Pfad den führenden "/" vergessen 


```
exec /home/minecraft/skript.sh start
```

Grüße,
BK


----------



## MoD2Cody (28. Februar 2014)

Nee, da hatte ich mich nur vertippt, anscheinend funktioniert es doch, allerdings nicht, wenn der Pfad gequotet ist also "" mit Anführungszeichen versehen ist. Naja Vielen Dank für alles! ^^

Gruß
Cody


----------

