Arsene
Arsene

Reputation: 1067

Shell Scripting issue

I am writing a shell script to make an application I have developped run as a service on Linux. The shell script I wrote works perfectly when I used the ./smpp-daemon.sh start. However when I want to use the following syntax : sh smpp-daemon.sh start I got the following error:/srv/smpp/bin/smpp-daemon.sh: 26: /srv/smpp/bin/smpp-daemon.sh: function: not found /srv/smpp/bin/smpp-daemon.sh: 27: local: not in a function.

This is the shell script:

#!/bin/bash
#
# Unity SMPP Daemon script
#
# Arsene Tochemey GANDOTE

# Set this to your Java installation
JAVA_HOME=/usr/lib/jvm/java-7-oracle

appNameLo="smpp"                               # application name with the first letter in lowercase
appName="SMPP"                                 # application name
osUser="root"                                    # OS user name for the service
osGroup="root"                                  # OS group name for the service
appHome="/srv/$appNameLo"                       # home directory of the service application
osUserHome="/$osUser"                           # home directory of the service user
appLogFile="/var/log/$appNameLo.log"                    # log file for StdOut/StdErr
maxShutdownTime=15                                  # maximum number of seconds to wait for the daemon to terminate normally
pidFile="/var/run/$appNameLo.pid"                   # name of PID file (PID = process ID number)
javaCommand="java"                                  # name of the Java launcher without the path
javaExe="$JAVA_HOME/bin/$javaCommand"               # file name of the Java application launcher executable
javaArgs="-jar $appHome/smsgh-smpp.jar"            # arguments for Java launcher
javaCommandLine="$javaExe $javaArgs"                # command line to start the Java service application
javaCommandLineKeyword="smsgh-smpp.jar"              # a keyword that occurs on the command line, used to detect an already running service process and to distinguish it from others

# Makes the file $1 writable by the group $osGroup.
function makeFileWritable {
   local filename="$1"
   touch $filename || return 1
   chgrp $osGroup $filename || return 1
   chmod g+w $filename || return 1
   return 0;
}

# Returns 0 if the process with PID $1 is running.
function checkProcessIsRunning {
   local pid="$1"
   if [ -z "$pid" -o "$pid" == " " ]; then return 1; fi
   if [ ! -e /proc/$pid ]; then return 1; fi
   return 0;
}

# Returns 0 if the process with PID $1 is our Java service process.
function checkProcessIsOurService {
   local pid="$1"
   if [ "$(ps -p $pid --no-headers -o comm)" != "$javaCommand" ]; then return 1; fi
   grep -q --binary -F "$javaCommandLineKeyword" /proc/$pid/cmdline
   if [ $? -ne 0 ]; then return 1; fi
   return 0;
}

# Returns 0 when the service is running and sets the variable $pid to the PID.
function getServicePID {
   if [ ! -f $pidFile ]; then return 1; fi
   pid="$(<$pidFile)"
   checkProcessIsRunning $pid || return 1
   checkProcessIsOurService $pid || return 1
   return 0;
}

function startServiceProcess {
   cd $appHome || return 1
   rm -f $pidFile
   makeFileWritable $pidFile || return 1
   makeFileWritable $appLogFile || return 1
   cmd="nohup $javaCommandLine >>$appLogFile 2>&1 & echo \$! >$pidFile"
   su -m $osUser -s $SHELL -c "$cmd" || return 1
   sleep 0.1
   pid="$(<$pidFile)"
   if checkProcessIsRunning $pid; then :; else
      echo -ne "\n$appName start failed, see logfile."
      return 1
   fi
   return 0; 
}

function stopServiceProcess {
   kill $pid || return 1
   for ((i=0; i<maxShutdownTime*10; i++)); do
      checkProcessIsRunning $pid
      if [ $? -ne 0 ]; then
         rm -f $pidFile
         return 0
         fi
      sleep 0.1
      done
   echo -e "\n$appName did not terminate within $maxShutdownTime seconds, sending SIGKILL..."
   kill -s KILL $pid || return 1
   local killWaitTime=15
   for ((i=0; i<killWaitTime*10; i++)); do
      checkProcessIsRunning $pid
      if [ $? -ne 0 ]; then
         rm -f $pidFile
         return 0
         fi
      sleep 0.1
      done
   echo "Error: $appName could not be stopped within $maxShutdownTime+$killWaitTime seconds!"
   return 1; 
}

function startService {
   getServicePID
   if [ $? -eq 0 ]; then echo -n "$appName is already running"; RETVAL=0; return 0; fi
   echo -n "Starting $appName   "
   startServiceProcess
   if [ $? -ne 0 ]; then RETVAL=1; echo "failed"; return 1; fi
   echo "started PID=$pid"
   RETVAL=0
   return 0; 
}

function stopService {
   getServicePID
   if [ $? -ne 0 ]; then echo -n "$appName is not running"; RETVAL=0; echo ""; return 0; fi
   echo -n "Stopping $appName   "
   stopServiceProcess
   if [ $? -ne 0 ]; then RETVAL=1; echo "failed"; return 1; fi
   echo "stopped PID=$pid"
   RETVAL=0
   return 0; 
}

function checkServiceStatus {
   echo -n "Checking for $appName:   "
   if getServicePID; then
  echo "running PID=$pid"
  RETVAL=0
   else
  echo "stopped"
  RETVAL=3
   fi
   return 0; 
}

function main {
   RETVAL=0
   case "$1" in
      start)                                               # starts the Java program as a Linux service
         startService
         ;;
      stop)                                                # stops the Java program service
         stopService
         ;;
      restart)                                             # stops and restarts the service
         stopService && startService
         ;;
      status)                                              # displays the service status
         checkServiceStatus
         ;;
      *)
         echo "Usage: $0 {start|stop|restart|status}"
         exit 1
         ;;
      esac
   exit $RETVAL
}

main $1

Please assist because I am not shell script geek. I can only get my way around.

Upvotes: 1

Views: 1856

Answers (2)

DevSolar
DevSolar

Reputation: 70223

Running as ./script uses the shell stated in the #! "shebang" line, or your default shell if no such line exists - the latter most likely being Bash.

Running as sh script overrides the default / shebang shell, and uses the Bourne shell instead - or, more likely, Bash in backward compatibility mode.

If your script uses Bash-isms (like local), they won't work in the second case.

You could, of course, call bash script...

Upvotes: 0

user268396
user268396

Reputation: 11976

The issue is twofold:

  1. Bash is not sh on Debian, Ubuntu, etc., so Bashishms won't work when you execute your script with sh. Debian uses dash for sh instead.
  2. The local keyword is not, in fact, standard POSIX sh. Dash thinks it is a function call.

Easy workaround: do not use local, make sure your variable names are unique. Sh scripting is not my forte, but from what I can tell it looks like simply removing the offending local keyword will do in your case.

Upvotes: 1

Related Questions