Bash Experts

Any BASH experts in here?

I have a very crude startup script made by using WEBMIN on my Raspberry Pi.  It starts up BLYNK

Now if I type the command line….

java -jar /var/blynk/server-0.10.2.jar -dataFolder /var/blynk &

That ampersand on the end will ensure my terminal program prompt comes back to me once the program is started up!!!

However, if I put that (and a change of directory which is necessary) into Webmin for a startup script…

It works ok – but the Raspberry Pi terminal comes up for login – but then starts this script – and stays in it – i.e. no more prompt - hitting Control C brings it back but of course the program has stopped.

Update: Wrapping in parentheses helps…. with that, one can get the prompt back by simply hitting ENTER and the program keeps running – but really, that’s not the answer. I don’t understand why this happens after the prompt first appears where all other services seem to be up and running before then. See comments…

My questions for script wizards are:

1. What do I need to change so that this will indeed run in the background like all the other items that Webmin has created

2. What can I change to add a STOP function to this?

#!/bin/sh
### BEGIN INIT INFO
# Provides: Blynk
# Required-Start: $network
# Required-Stop: $network
# Default-Start: 2 3 5
# Description:
### END INIT INFO

case "$1" in
'start')
    cd /var/blynk
    java -jar /var/blynk/server-0.10.2.jar -dataFolder /var/blynk &
    ;;
'stop')
    ;;
*)
    echo "Usage: $0 { start | stop }"
    ;;
esac
exit 0

Facebooktwittergoogle_pluspinterestlinkedin

24 thoughts on “Bash Experts

  1. This is the script I use to start and stop a java program on Ubuntu.

    It's by no means as good as could be. Just as good as needed to be.

    #!/bin/bash

    NAME=JLogArchive.jar
    ARGS='-p 2400 -t 1000 -d /var/log/tc65/csv/'

    ####################################
    # Do not edit below this point #
    ####################################

    PROGRAM=/usr/local/bin/$NAME
    PID_FILE=/var/run/$NAME.pid

    if [ ! -f $PROGRAM ]
    then
    echo "$PROGRAM not found"
    exit 1
    fi

    function GetPID {
    PID=`ps aux | grep $1 | grep -v grep | awk '{ print($2) }'`
    }

    GetPID $NAME

    case "$1" in
    'start')
    if [ -n "$PID" ] ; then
    echo "$NAME is already running";
    else
    java -jar $PROGRAM $ARGS &
    if [ $? -eq 0 ] ; then
    GetPID $NAME
    echo $PID > $PID_FILE
    echo started;
    fi
    fi
    ;;
    'stop')
    if [ -n "$PID" ] ; then
    /bin/kill $PID;
    rm $PID_FILE
    echo 'stopped';
    else
    echo "$NAME is not running"
    fi
    ;;
    'restart')
    /bin/kill $PID;
    rm $PID_FILE
    java -jar $PROGRAM $ARGS &
    if [ $? -eq 0 ] ; then
    GetPID $NAME
    echo $PID > $PID_FILE
    echo restarted;
    else
    echo Not restarted;
    fi
    ;;
    *)
    echo "Usage: $0 { start | stop | restart}"
    exit 1
    ;;
    esac

    exit 0

      1. Ok I think I've turned off that smart quote nonsense. Here is my variation of your script Johan

        #!/bin/bash

        NAME=server-0.10.2.jar
        ARGS='-dataFolder /var/blynk'
        WORKFOLDER='/var/blynk'

        ####################################
        # Do not edit below this point #
        ####################################

        PROGRAM=/var/blynk/$NAME
        PID_FILE=/var/blynk/$NAME.pid

        if [ ! -f $PROGRAM ]
        then
        echo "$PROGRAM not found"
        exit 1
        fi

        function GetPID {
        PID=`ps aux | grep $1 | grep -v grep | awk '{ print($2) }'`
        }

        GetPID $NAME

        case "$1" in
        'start')
        if [ -n "$PID" ] ; then
        echo "$NAME is already running";
        else
        cd $WORKFOLDER
        java -jar $PROGRAM $ARGS &
        if [ $? -eq 0 ] ; then
        GetPID $NAME
        echo $PID > $PID_FILE
        echo started;
        fi
        fi
        ;;
        'stop')
        if [ -n "$PID" ] ; then
        /bin/kill $PID;
        rm $PID_FILE
        echo 'stopped';
        else
        echo "$NAME is not running"
        fi
        ;;
        'restart')
        /bin/kill $PID;
        rm $PID_FILE
        java -jar $PROGRAM $ARGS &
        if [ $? -eq 0 ] ; then
        GetPID $NAME
        echo $PID > $PID_FILE
        echo restarted;
        else
        echo Not restarted;
        fi
        ;;
        *)
        echo "Usage: $0 { start | stop | restart}"
        exit 1
        ;;
        esac

        exit 0

        The problem is - when I reboot the Pi, I can see everything booting up - then the prompt comes up - and then a few seconds later..... "Blynk server successfully started..." - and the prompt disappears... I haveto hit control-C to get out of it... it's STILL doing it...

    1. There's no need for ps to get the pid of a backgrounded command, just hang onto it after it's executed:

      ```
      java -jar $PROGRAM $ARGS &
      PID=#!
      ```

  2. Pete, do you really need to press control+c, or pressing Enter would suffice? Sometimes tasks that were put in background continue to send messages to the terminal, without blocking it. In this case, you could get a new prompt line simply pressing Enter. That being the case, you can also avoid completely the unwanted messages in your terminal by adding '> /dev/null' before the & on your script.

    1. No, enter just ends up with a blank line.. you have to hit Control-C to get out of it and that stops it running - all the hallmarks of a foreground process - yet the same thing done at the command line works!!

      1. Exactly as written; i.e. your original line including the ampersand all enclosed in parentheses, with another ampersand at the end of the line.

        1. A second ampersand here failed - produced a red "failed" message at the prompt

          cd $WORKFOLDER
          java -jar $PROGRAM $ARGS & &

          This version

          cd $WORKFOLDER
          (java -jar $PROGRAM $ARGS) &

          i.e. adding parentheses made some difference, the prompt was still missing, but simply hitting ENTER brought it back and the service continued to run.

          Neither of these can be right - services don't normally have such an interaction at the command line?

          1. Hi this is what I tried (I'm hoping my changes to wordpress will stop this messing up)

            else
            cd $WORKFOLDER
            (java -jar $PROGRAM $ARGS &) &
            if [ $? -eq 0 ] ; then

            So the two lines in the middle there are as suggested.

            The result..
            [FAIL[startpar: service(s) returned failure: Blynk ... failed!

  3. I'm at work and don't have access to my Pi right now. But see if your system has a command called start-stop-daemon. This is what a lot of init scripts on my Ubuntu system use.

    For that matter, look at the other scripts in /etc/init.d for examples?

  4. For part 1, there are a few simple ways to get the behavior you're looking for. The simplest is to just wrap the whole sequence in parens so all commands inside are executed in a subshell. This works as long as you're not expecting anything in the current shell env to be modified by the commands. Your example was backgrounding already, and you didn't mention doing anything with the results afterward, so give this a shot first:
    ```
    ( pushd /some/path ; ./script.sh --arrrg ; popd; ) &
    ```

    If that won't work, there are more things to try.

    1. Hi Ian - it wasn't backgrounding - that's the problem. so if i disable it - all works well on reboot (but no BLYNK) and the command prompt appears on the PI. If I enable that script - I would have expected the same - but what was ACTUALLY happening was that the prompt was appearing - seconds later the starup message for BLYNK would appear and the prompt was no longer available without hitting control-C - I thought the point of the ampersand on the end was to avoid that.

  5. Here's a full example in context:

    ```
    #!/bin/bash

    NAME=server-0.10.2.jar
    ARGS='-dataFolder /var/blynk'
    WORKFOLDER='/var/blynk'

    ####################################
    # Do not edit below this point #
    ####################################

    PROGRAM=/var/blynk/$NAME
    PID_FILE=/var/blynk/$NAME.pid

    if [ ! -f $PROGRAM ]
    then
    echo "$PROGRAM not found"
    exit 1
    fi

    [ -f "$PID_FILE" ] && PID="$( $PID_FILE
    echo 'started'
    fi
    ;;
    'stop')
    if [ -n "$PID" ] ; then
    /bin/kill -15 $PID
    rm -f $PID_FILE
    echo 'stopped'
    else
    echo "$NAME is not running"
    fi
    ;;
    'restart')
    [ -n "$PID" ] && /bin/kill -15 $PID
    ( cd $WORKFOLDER ; /usr/bin/java -jar $PROGRAM $ARGS ) &
    PID=$!
    echo "$PID" > $PID_FILE
    echo 'restarted'
    ;;
    *)
    echo "Usage: $0 { start | stop | restart}"
    exit 1
    ;;
    esac

    exit 0
    ```

  6. Let's try that again (looks like angle brackets are interpreted as html tags). Here's a full-context example (not tested, might need some debuggery):

    ----------
    #!/bin/bash

    NAME='server-0.10.2.jar'
    ARGS='-dataFolder /var/blynk'
    WORKFOLDER='/var/blynk'

    ####################################
    # Do not edit below this point #
    ####################################

    PROGRAM="/var/blynk/$NAME"
    PID_FILE="/var/blynk/$NAME.pid"

    if [ ! -f $PROGRAM ]; then
    echo "$PROGRAM not found"
    exit 1
    fi

    [ -f "$PID_FILE" ] && PID="$(<$PID_FILE)"

    case "$1" in
    'start')
    if [ -n "$PID" ]; then
    echo "$NAME is already running"
    else
    ( cd $WORKFOLDER ; /usr/bin/java -jar $PROGRAM $ARGS ) &
    PID=$!
    echo "$PID" > "$PID_FILE"
    echo 'started';
    fi
    ;;

    'stop')
    if [ -n "$PID" ]; then
    /bin/kill -15 $PID
    rm -f "$PID_FILE"
    echo 'stopped'
    else
    echo "$NAME is not running"
    fi
    ;;

    'restart')
    [ -n "$PID" ] && /bin/kill -15 $PID
    ( cd $WORKFOLDER ; /usr/bin/java -jar $PROGRAM $ARGS ) &
    PID=$!
    echo "$PID" > "$PID_FILE"
    echo 'restarted'
    ;;

    *)
    echo "Usage: $0 { start | stop | restart}"
    exit 1
    ;;
    esac

    exit 0
    ----------

  7. Hi,

    maybe this will work:
    $ nohup java -jar /var/blynk/server-0.10.2.jar -dataFolder /var/blynk &>/dev/null &

    This should start it up and detach it from the terminal (and redirect any output to /dev/null).

    Hope it helps,
    Pedro

    1. Yes indeed it does! That pretty much cracks it - put in perspective here's the entire start/stop/restart script for Blynk which now seems to work. Thanks for the top Pedro.

      #!/bin/bash

      NAME=server-0.10.2.jar
      ARGS='-dataFolder /var/blynk'
      WORKFOLDER='/var/blynk'

      ####################################
      # Do not edit below this point #
      ####################################

      PROGRAM=/var/blynk/$NAME
      PID_FILE=/var/blynk/$NAME.pid

      if [ ! -f $PROGRAM ]
      then
      echo "$PROGRAM not found"
      exit 1
      fi

      function GetPID {
      PID=`ps aux | grep $1 | grep -v grep | awk '{ print($2) }'`
      }

      GetPID $NAME

      case "$1" in
      'start')
      if [ -n "$PID" ] ; then
      echo "$NAME is already running";
      else
      cd $WORKFOLDER
      nohup java -jar $PROGRAM $ARGS &>/dev/null &
      # (java -jar $PROGRAM $ARGS &)
      if [ $? -eq 0 ] ; then
      GetPID $NAME
      echo $PID > $PID_FILE
      echo started;
      fi
      fi
      ;;
      'stop')
      if [ -n "$PID" ] ; then
      /bin/kill $PID;
      rm $PID_FILE
      echo 'stopped';
      else
      echo "$NAME is not running"
      fi
      ;;
      'restart')
      /bin/kill $PID;
      rm $PID_FILE
      cd $WORKFOLDER
      nohup java -jar $PROGRAM $ARGS &>/dev/null &
      # (java -jar $PROGRAM $ARGS &)
      if [ $? -eq 0 ] ; then
      GetPID $NAME
      echo $PID > $PID_FILE
      echo restarted;
      else
      echo Not restarted;
      fi
      ;;
      *)
      echo "Usage: $0 { start | stop | restart}"
      exit 1
      ;;
      esac

      exit 0

  8. Looks like you have this licked, but beware, there are differences between shell and bash i.e. #!/bin/sh and #!/bin/bash

    1. Also I think it is best to use ./command_name - that's because (unlike in Windows), the current directory isn't part of your path by default.

      If the start is early in the boot sequence then the path might not even be set up at all, so I would recommend always using the full path in a script.

Leave a Reply

Your email address will not be published. Required fields are marked *