Why is the $ sign used in this bash script - linux

I'm looking on Fedora sysV init script example and it goes like this:
#...some code
start() {
[ -x $exec ] || exit 5
[ -f $config ] || exit 6
echo -n $"Starting $prog: "
# if not running, start it up here, usually something like "daemon $exec"
retval=$?
echo
[ $retval -eq 0 ] && touch $lockfile
return $retval
}
#...some more code....
What is the reason for first dollar sign in this line, because it seems that script will work perfectly fine without it - will it not?
echo -n $"Starting $prog: "

$"..." is an extension that allows you to use gettext i18n in bash scripts.

Related

Terminal Freezing after Bash Script Succeeded

I have a pretty simple bash script that coordinates running a couple python scripts. What I am having trouble figuring out is why after running the bash script (. bash_script.sh), the terminal hangs. I can't ctrl+c, ctrl+z or do anything except restart the SSH session. All I see is just a blinking cursor. Checking all the log files indicates a 0 status exit code with no errors in the scripts themselves. Running ps aux | grep bash_script.sh does not show any anything running either. Is there anyway to debug this?
#!/bin/bash
exec >> <DIR>/logfile.log 2>&1
script_message () {
status_arg=$1
if [[ $status_arg = "pass" ]]; then
printf "Script Done\n"
printf '=%.0s' {1..50}
printf "\n"
elif [[ $status_arg = "fail" ]]; then
printf "Script Failed\n"
printf '=%.0s' {1..50}
printf "\n"
else
:
fi
}
current_date=$(date '+%Y-%m-%d %H:%M:%S')
day=$(date +%u)
hour=$(date +%H)
printf "RUN DATE: $current_date\n"
# activate virtual env
source /<VENV DIR/bin/activate>
python <PYTHON SCRIPT>.py >> <DIR>/logfile2.log 2>&1
retVal=$?
if [[ $retVal -eq 0 && $day -eq 4 ]]; then
python <PYTHON SCRIPT 2>.py >> <DIR>/logfile3.log 2>&1
script_message pass
elif [[ $retVal -eq 0 ]]; then
script_message pass
else
#:
script_message fail
fi
echo $?

Change exit code on a single line using Bash?

I am using the savscan command but this returns 3 instead of 1 when a malware is detected, and I need to get 1 if a malware is detected, I tried the following:
$ bash -c "savscan -f -archive infectedfile.exe && if [ $? -eq 3 ]; then exit 1 ; fi"
$ echo $?
$ 0
$ bash -c "savscan -f -archive infectedfile.exe ; if [ $? -eq 3 ]; then exit 1 ; fi"
$ echo $?
$ 0
but I still get the exit code 0, I also need to run everything in one line
Personally, I'd use a function wrapper for this:
savscan() {
local retval
command savscan "$#"; retval=$?
(( retval == 3 )) && retval=1
return "$retval"
}
savscan -f -archive infectedfile.exe
...as adding more rules about how to mutate your exit status is as simple as adding additional commands inspecting and modifying retval, as you see fit.
If you for some reason insist on defining and invoking this function in a single line, this could look like:
savscan() { local retval; command savscan "$#"; retval=$?; (( retval == 3 )) && retval=1; return "$retval"; }; savscan -f -archive infectedfile.exe
Why not test the return status of bash command and adjust as needed.
bash -c "savscan -f -archive infectedfile.exe" || [ $? -ne 3 ]
My tests:
$ bash -c "savscan -f -archive infectedfile.exe" || [ $? -ne 3 ]
$ echo $?
1
$ bash -c "savscan -f -archive okfile.exe" || [ $? -ne 3 ]
$ echo $?
0

Php script as daemon

I am new to php daemons. I am using the below script to fire Daemon.php script. But i am getting error while executing this below bash script via shell
The error is,
exit: 0RETVAL=0: numeric argument required
Please help me resolve this error
#!/bin/bash
#
# /etc/init.d/Daemon
#
# Starts the at daemon
#
# chkconfig: 345 95 5
# description: Runs the demonstration daemon.
# processname: Daemon
# Source function library.
#. /etc/init.d/functions
#startup values
log=/var/log/Daemon.log
#verify that the executable exists
test -x /home/godlikemouse/Daemon.php || exit 0RETVAL=0
#
# Set prog, proc and bin variables.
#
prog="Daemon"
proc=/var/lock/subsys/Daemon
bin=/home/godlikemouse/Daemon.php
start() {
# Check if Daemon is already running
if [ ! -f $proc ]; then
echo -n $"Starting $prog: "
daemon $bin --log=$log
RETVAL=$?
[ $RETVAL -eq 0 ] && touch $proc
echo
fi
return $RETVAL
}
stop() {
echo -n $"Stopping $prog: "
killproc $bin
RETVAL=$?
[ $RETVAL -eq 0 ] && rm -f $proc
echo
return $RETVAL
}
restart() {
stop
start
}
reload() {
restart
}
status_at() {
status $bin
}
case "$1" in
start)
start
;;
stop)
stop
;;
reload|restart)
restart
;;
condrestart)
if [ -f $proc ]; then
restart
fi
;;
status)
status_at
;;
*)
echo $"Usage: $0 {start|stop|restart|condrestart|status}"
exit 1
esac
exit $?
exit $RETVAL
This line produces the error:
test -x /home/godlikemouse/Daemon.php || exit 0RETVAL=0
If you want to set the the value of RETVAL to 0 you first need to remove the 0 as you can not have variables that start with a number.
Then you remove the value set from the second statement so it will exit in case Daemon.php does not exist.
test -x /home/godlikemouse/Daemon.php || exit
You can also remove the 2 empty echo statements inside the start and stop functions as the do nothing.
There are also errors in the case statement. You need to quote the case options and can remove the last exit block as the exit $? will trigger the exit before.
case "$1" in
"start")
start
;;
"stop")
stop
;;
"reload"|"restart")
restart
;;
"condrestart")
if [ -f $proc ]; then
restart
fi
;;
"status")
status_at
;;
There is several syntax and logic errors in this script presented. To highlight several:
echo $"Usage (should be just echo "Usage ..." since the string in ".." is not a variable
Double exit statements, the second one for $RETVAL is never ran.
exit 0RETVAL is not the same as exit $RETVAL, and one should just be using exit 1 instead to denote an error, exit 0 means the script ran correctly
$prog is defined but never used
test -x is to check for executable bit enabled in the given path. test -f is safer when testing for a file, test -d safer for testing directories, and test -L is safer when testing symlinks. Combine the test -f and test -x to ensure there is no race conditions or worst. (example: (test -f /home/godlikemouse/Daemon.php && test -x /home/godlikemouse/Daemon.php) || exit 1))
Further details on creating sysv init scripts can be read at http://refspecs.linuxbase.org/LSB_3.0.0/LSB-generic/LSB-generic/iniscrptact.html and bash scripting can be read at http://www.tldp.org/LDP/abs/html/index.html. It is strongly encouraged to learn both before writing system control programs such as init scripts.

difference between init and control script?

I am writing a script, for the first time. I followed few examples and I have my init script and then a control script that uses the loop option, to create a copy if itself and start the final application.
My questions are:
1. What is the difference between an init script and a control script? Why is better to implement them separately?
2. Why do I need to create a copy of the control script to start the application (loop), why not do it directly with the control script? What are the benefits of doing it like this?
3. How could I improve my scripts? For example I don't know if using directly kill -9 is the best option, I have read few comments against it..
My init script is very basic:
#!/bin/bash
APPCTL="/home/app/appctl"
APPBIN="/home/app/app.cpp"
if [ ! -x "$APPCTL" -o ! -f "$APPBIN" ]; then
echo "ERROR: app is missing or is not executable" >&2
exit 1
fi
if [ "$1" = "stop" -o "$1" = "restart" ]; then
echo "Stopping app"
"$APPCTL" stop
fi
if [ "$1" = "start" -o "$1" = "restart" ]; then
echo "Starting app"
"$APPCTL" start
fi
My control script is the following:
#!/bin/sh
APP_DIR="/home/app"
APP_CTL="$APP_DIR/appctl"
APP_BIN="$APP_DIR/app.cpp"
APPCLT_PID="/var/run/appctl.pid"
OWN_PID=$$
case "$1" in
start)
if [ -f "$APPCLT_PID" ]; then
PID=$(cat "$APPCLT_PID")
fi
if [ "$PID" != "" ]; then
COMM=$(ps --pid "$PID" ho comm)
if [ "$COMM" == "appctl" ]; then
echo "Already runnning..."
exit 0
fi
fi
"$APP_CTL" loop 2>&1 &
;;
stop)
if [ -f "$APPCLT_PID" ]; then
PID=$(cat $APPCLT_PID)
if [ "$PID" != "" ]; then
kill -9 "$PID"
fi
rm -f "$APPCLT_PID"
fi
for pid in $(pgrep -f $APP_BIN); do
kill $pid
done
;;
loop)
echo $OWN_PID > "$APPCLT_PID"
cd "$APP_DIR"
while true; do
nice -n 10 "$APP_BIN" > /dev/null 2>&1
sleep 5
done
;;
esac
exit 0
Thanks.

Grace period in bash init.d script before killing process when calling '/etc/init.d/daemon stop'

I'm modifying an init.d script for one of my company apps. Apparently my bash script foo is not strong enough.
Once the Launcher has seen the Dispatcher has terminated, it will exit. The vanilla script always displays [ FAILED ] when stopping the app as the Launcher has terminated before this script tries to kill it.
I've tried to add in a 2 second grace period (plenty) for the Launcher to terminate before attempting to kill it if it's still running.
I have the following stop() function:
#!/bin/bash
# chkconfig: 345 85 60
# description: .
# processname: xxx
# pidfile: /var/run/xxx.pid
# Source function library.
. /etc/rc.d/init.d/functions
RETVAL=0
PID_PATH=/tmp/
PID_PREFIX=xxx
LOCK_PATH=/tmp/
PIDFILE_D=${PID_PATH}${PID_PREFIX}_dispatcher.pid
PIDFILE_L=${PID_PATH}${PID_PREFIX}_launcher.pid
PIDFILE_J=${PID_PATH}${PID_PREFIX}_jobselector.pid
LOCK=${LOCK_PATH}${PID_PREFIX}
BASEPATH=`dirname $0`
echo $BASEPATH | grep -q "^/" && BASEPATH=`dirname $BASEPATH` || BASEPATH=$PWD/`dirname $BASEPATH`
# -- snip ---
stop() {
echo -n $"Shutting down Dispatcher: "
killproc -p $PIDFILE_D
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f $PIDFILE_D
echo -n $"Shutting down Launcher: "
# launcher self terminates once it sees the dispatcher is not running
# grace period of 2 seconds before explicitly killing it
if [ -e "$PIDFILE_L" ]; then
local i pid
read pid < "$PIDFILE_L"
for i in 1 2; do
if checkpid $pid 2>&1; then
sleep 1
fi
done
# if launcher still active after grace period, kill it
if checkpid $pid 2>&1; then
killproc -p $PIDFILE_L
RETVAL=$?
else
success $"$base shutdown"
fi
else
success $"$base shutdown"
fi
[ $RETVAL -eq 0 ] && rm -f $PIDFILE_L
echo -n $"Shutting down Job Selector: "
killproc -p $PIDFILE_J
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f $PIDFILE_J
[ $RETVAL -eq 0 ] && rm -f $LOCK
return $RETVAL
}
When I stop the program, it doesn't display the "Shutting down Launcher: ... " line anymore.
$ sudo ./bin/program stop
Shutting down Dispatcher: [ OK ]
Shutting down Job Selector: [ OK ]
Supporting functions:
killproc() {
local RC killlevel= base pid pid_file= delay
RC=0; delay=3
# Test syntax.
if [ "$#" -eq 0 ]; then
echo $"Usage: killproc [-p pidfile] [ -d delay] {program} [-signal]"
return 1
fi
if [ "$1" = "-p" ]; then
pid_file=$2
shift 2
fi
if [ "$1" = "-d" ]; then
delay=$2
shift 2
fi
# check for second arg to be kill level
[ -n "${2:-}" ] && killlevel=$2
# Save basename.
base=${1##*/}
# Find pid.
__pids_var_run "$1" "$pid_file"
if [ -z "$pid_file" -a -z "$pid" ]; then
pid="$(__pids_pidof "$1")"
fi
# Kill it.
if [ -n "$pid" ] ; then
[ "$BOOTUP" = "verbose" -a -z "${LSB:-}" ] && echo -n "$base "
if [ -z "$killlevel" ] ; then
if checkpid $pid 2>&1; then
# TERM first, then KILL if not dead
kill -TERM $pid >/dev/null 2>&1
usleep 100000
if checkpid $pid && sleep 1 &&
checkpid $pid && sleep $delay &&
checkpid $pid ; then
kill -KILL $pid >/dev/null 2>&1
usleep 100000
fi
fi
checkpid $pid
RC=$?
[ "$RC" -eq 0 ] && failure $"$base shutdown" || success $"$base shutdown"
RC=$((! $RC))
# use specified level only
else
if checkpid $pid; then
kill $killlevel $pid >/dev/null 2>&1
RC=$?
[ "$RC" -eq 0 ] && success $"$base $killlevel" || failure $"$base $killlevel"
elif [ -n "${LSB:-}" ]; then
RC=7 # Program is not running
fi
fi
else
if [ -n "${LSB:-}" -a -n "$killlevel" ]; then
RC=7 # Program is not running
else
failure $"$base shutdown"
RC=0
fi
fi
# Remove pid file if any.
if [ -z "$killlevel" ]; then
rm -f "${pid_file:-/var/run/$base.pid}"
fi
return $RC
}
# Check if $pid (could be plural) are running
checkpid() {
local i
for i in $* ; do
[ -d "/proc/$i" ] && return 0
done
return 1
}
# Log that something succeeded
success() {
#if [ -z "${IN_INITLOG:-}" ]; then
# initlog $INITLOG_ARGS -n $0 -s "$1" -e 1
#fi
[ "$BOOTUP" != "verbose" -a -z "${LSB:-}" ] && echo_success
return 0
}
echo_success() {
[ "$BOOTUP" = "color" ] && $MOVE_TO_COL
echo -n "["
[ "$BOOTUP" = "color" ] && $SETCOLOR_SUCCESS
echo -n $" OK "
[ "$BOOTUP" = "color" ] && $SETCOLOR_NORMAL
echo -n "]"
echo -ne "\r"
return 0
}
What is the relevance of $ is in the echo line?
echo -n $"Shutting down Launcher: "
If I add in the debug line:
echo "RETVAL=$RETVAL"
[ $RETVAL -eq 0 ] && rm -f $PIDFILE_L
I get:
Shutting down Dispatcher: [FAILED]
RETVAL=0 down Launcher: [ OK ]
Shutting down Job Selector: [FAILED]
Any bash script gurus out there?
Turns out all I needed was an echo statement before the following line.
echo
[ $RETVAL -eq 0 ] && rm -f $PIDFILE_L
This is related to my question about the behaviour of echo -n $"Shutting down Launcher".
The echo -n switch supresses the line feed character \n. The $ preceding the quotes outputs carriage return \r to move the cursor back to the beginning of the line.
Without the echo statement, the Job Selector shutdown line was overwriting the Launcher shutdown line.

Resources