Escaping variables in bash file - linux

I'm creating a init.d script within a bash file, which goes as follows:
# AUTOSTART
$APPDIR=somedir
$APPCONF=somedir
$APPVENV=somedir
$APPUSER=someuser
cat <<EOF >/etc/init.d/uwsgi
#!/bin/bash
daemon=$APPVENV/bin/uwsgi
args="--emperor $APPCONF/uwsgi/app.ini --daemonize /var/log/emperor.log --emperor-pidfile $APPDIR/emperor.pid --gid `id -g $APPUSER`"
pid=$APPDIR/emperor.pid
case "$1" in
start)
echo "Starting uwsgi"
start-stop-daemon -m -p $pid --start --exec $daemon $args
;;
stop)
echo "Stopping script uwsgi"
start-stop-daemon --signal INT -p $pid --stop $daemon $args
;;
reload)
echo "Reloading conf"
kill -HUP $(cat $pid)
;;
*)
echo "Usage: /etc/init.d/uwsgi {start|stop|reload}"
exit 1
;;
esac
exit 0
EOF
It is my understanding, from help, that $APPCONF, $APPVENV, $APPUSER and $APPDIR need to be escaped because I define them outside the file. So is it correct that I simply put a back slash in front of the variable like this:
daemon=\$APPVENV/bin/uwsgi
args="--emperor \$APPCONF/uwsgi/app.ini --daemonize /var/log/emperor.log --emperor-pidfile \$APPDIR/emperor.pid --gid `id -g \$APPUSER`"
pid=\$APPDIR/emperor.pid
It still doesn't seem to work though, the service doesn't start, so I think I might have done something else wrong. Can anyone confirm I am escaping properly please?

The dollar sign is only used for reading/using the value of a variable, not when setting its value. Thus, setting APPDIR to somedir would look like this:
APPDIR=somedir
Depending on how you call the script, you may also want to export the variable:
export APPDIR=somedir

Related

How to kill all processes named "shairport" that do not have the pid 12345

I am using shairport at work to stream music. I am running it on a Debian machine(a raspberry). In its /etc/init.d/shairport file it has only the start|stop commands.
I want to add a restart one. Here is the code so far:
case "$1" in
restart)
service shairport stop
service shairport start
;;
start)
/usr/local/bin/shairport -d -a "$NAME" -p 5002 -k "madafaka" -w -B "mpc stop"
;;
stop)
killall shairport
;;
*)
echo "Usage: /etc/init.d/shairport {start|stop|restart}"
exit 1
;;
esac
exit 0
The issue is that when I run "service shairport restart", the service is stopped, thus running "killall shairport" and killing the bash script process itself. So "start" is never executed.
How do I make killall kill every shairport except the current script?
My idea was to get the pid and exclude it, but I cant find how to do that.
The start part should write down the PID of the started process.
Something like echo $? > /var/run/shairport.pid will do.
Stop part of your script will use the PID from the .pid file we have created, and kill the right process. This is what most of Linux services do as far as I know.
In linux you can know the process ID that the script file is running under with : $$.
You just have to check you're not killing yourself with :
stop)
for pid in $(pgrep shairport); do
if[$pid != $$]
kill $pid
fi
done
Since the answer I chose did not work straight out of the box, here is the code I ended up with:
case "$1" in
restart)
for pid in $(pgrep shairport); do
if [ "$pid" != $$ ]; then
kill $pid
fi
done
/usr/local/bin/shairport -d -a "$NAME" -p 5002 -k "madafaka" -w -B "mpc stop"
;;
start)
/usr/local/bin/shairport -d -a "$NAME" -p 5002 -k "madafaka" -w -B "mpc stop"
;;
stop)
killall shairport
;;
*)
echo "Usage: /etc/init.d/shairport {start|stop|restart}"
exit 1
;;
esac

My custom init shell script stops deployment script

I have a deployment script which works fine. At the end of it I added this block:
cat << EOF > /etc/init.d/uwsgi
#!/bin/bash
daemon=$APPVENV/bin/uwsgi
args="--emperor $APPCONF/uwsgi/app.ini --daemonize /var/log/emperor.log --emperor-pidfile $APPDIR/emperor.pid --gid `id -g $APPUSER`"
pid=$APPDIR/emperor.pid
case "$1" in
start)
echo "Starting uwsgi"
start-stop-daemon -p $pid --start --exec $daemon -- $args
;;
stop)
echo "Stopping script uwsgi"
start-stop-daemon --signal INT -p $pid --stop $daemon -- $args
;;
reload)
echo "Reloading conf"
kill -HUP $(cat $pid)
;;
*)
echo "Usage: /etc/init.d/uwsgi {start|stop|reload}"
exit 1
;;
esac
exit 0
EOF
Now when I run my deployment script it gets stuck here, and I just see a blinking cursor and it doesn't run any lines after it.
Have I done anything wrong with my formatting, as I know creating a file with cat was something very picky about how it was formatted, tabulated etc.
variables are still substituted in heredocs, also subshelling with $( ), which you do in your script here:
kill -HUP $(cat $pid)
your installer attempts to cat that file, with $pid probably empty, therefore it waits for input from standard input.
You want to escape those "$" to prevent expansion, like
\$(cat \$foo)
And of course with all those variables you don't want to get expanded during installation too.

Init.d script doesn't start or stop only prints help message

I've tried to write a custom upstart script for uwsgi emperor but it doesn't seem to start uwsgi and only says Usage: /etc/init.d/uwsgi {start|stop|reload} when I try to run it using "service uwsgi start".
Can anyone please tell me where I have gone wrong. The snippet below is from my deployment shell script:
cat <<EOF >/etc/init.d/uwsgi
#!/bin/bash
daemon=\$APPVENV/bin/uwsgi
args="--emperor \$APPCONF/uwsgi/app.ini --daemonize /var/log/emperor.log --emperor-pidfile \$APPDIR/emperor.pid --gid `id -g \$APPUSER`"
pid=\$APPDIR/emperor.pid
case "$1" in
start)
echo "Starting uwsgi"
start-stop-daemon -m -p \$pid --start --exec \$daemon \$args
;;
stop)
echo "Stopping script uwsgi"
start-stop-daemon --signal INT -p \$pid --stop \$daemon \$args
;;
reload)
echo "Reloading conf"
kill -HUP \$(cat \$pid)
;;
*)
echo "Usage: /etc/init.d/uwsgi {start|stop|reload}"
exit 1
;;
esac
exit 0
EOF
chmod u+x /etc/init.d/uwsgi
update-rc.d uwsgi defaults
service uwsgi start
Use the following. Pay close attention to which $ I escape and do not escape.
cat <<EOF >/etc/init.d/uwsgi
#!/bin/bash
daemon="$APPVENV/bin/uwsgi"
args=( --emperor "$APPCONF/uwsgi/app.ini"
--daemonize /var/log/emperor.log
--emperor-pidfile "$APPDIR/emperor.pid" --gid \$(id -g "$APPUSER")
)
pid="$APPDIR/emperor.pid"
case "\$1" in
start)
echo "Starting uwsgi"
start-stop-daemon -m -p \$pid --start --exec \$daemon \$args
;;
stop)
echo "Stopping script uwsgi"
start-stop-daemon --signal INT -p \$pid --stop \$daemon \$args
;;
reload)
echo "Reloading conf"
kill -HUP \$(< \$pid)
;;
*)
echo "Usage: /etc/init.d/uwsgi {start|stop|reload}"
exit 1
;;
esac
exit 0
EOF
chmod u+x /etc/init.d/uwsgi
update-rc.d uwsgi defaults
service uwsgi start
Variables like APPDIR, based on your previous questions, are used to configure what is actually written to disk, so you leave them unescaped so that they are expanded when /etc/init.d/uwsgi is written.
Variables like daemon, $1, and the command substitutions $(id -g "$APPUSER") are intended to be expanded when the init script runs, so you want the literal string $daemon to appear in the script, not the value of $daemon (which is probably undefined) when uwsgi is written.
You forgot to escape the $1 like you did in other places in your script:
case "\$1" in
As you are using cat to create the script, you need to escape all instances of $
Check if the service start really does send an argument to your script:
*)
echo "Argument taken was \"$1\"."
echo "Usage: /etc/init.d/uwsgi {start|stop|reload}"
exit 1
It could actually be different and you may consider making changes based from it.

Start Stop Daemon Init Debian - Unrecognized arguments

This is my debian init script so far to start uwsgi in emperor mode:
cat <<EOF >/etc/init.d/uwsgi
#!/bin/bash
daemon="$APPVENV/bin/uwsgi"
args=( --emperor "$APPCONF/uwsgi/app.ini"
--daemonize /var/log/emperor.log
--emperor-pidfile "$APPDIR/emperor.pid" --gid \$(id -g "$APPUSER")
)
pid="$APPDIR/emperor.pid"
case "\$1" in
start)
echo "Starting uwsgi"
start-stop-daemon -m -p \$pid --start --exec \$daemon \$args
;;
stop)
echo "Stopping script uwsgi"
start-stop-daemon --signal INT -p \$pid --stop \$daemon \$args
;;
reload)
echo "Reloading conf"
kill -HUP \$(< \$pid)
;;
*)
echo "Usage: /etc/init.d/uwsgi {start|stop|reload}"
exit 1
;;
esac
exit 0
EOF
chmod u+x /etc/init.d/uwsgi
update-rc.d uwsgi defaults
service uwsgi start
When I run this command I get this response:
> service uwsgi stop
Stopping script uwsgi
start-stop-daemon: unrecognized option '--emperor'
Try 'start-stop-daemon --help' for more information.
However, I know --emperor is a perfectly valid argument of uwsgi. So what's going on, am I putting the uwsgi arguments in the wrong place?
Any help would be appreciated.

Why this bash script can't get the pid of the background process by $!

I have a script like that:
su lingcat -c PHPRC\=\/home\/lingcat\/etc\/php5\
PHP_FCGI_CHILDREN\=4\ \/usr\/bin\/php\-loop\.pl\ \/usr\/bin\/php5\-cgi\ \-b\
127\.0\.0\.1\:9006\ \>\>\/home\/lingcat\/logs\/php\.log\ 2\>\&1\ \<\/dev\/null\ \&\
echo\ \$\!\ \>\/var\/php\-nginx\/135488849520817\.php\.pid
This is working. But there is too many \ in the script, they make the code unreadable. So, I wrote a new shell script:
#!/bin/sh
case "$1" in
'start')
su biergaizi -c "PHPRC=/home/biergaizi/etc/php5 PHP_FCGI_CHILDREN=2
/usr/bin/php-loop.pl /usr/bin/php-cgi -b /var/run/virtualhost/php5-fpm-biergaizi.test.sock >>/home/biergaizi/logs/php.log 2>&1 </dev/null &
echo $! > /var/php-nginx/biergaizi.test.php.pid"
RETVAL=$?
;;
'stop')
su biergaizi -c "kill `cat /var/php-nginx/biergaizi.test.php.pid` ; sleep 1"
RETVAL=$?
;;
'restart')
$0 stop ; $0 start
RETVAL=$?
;;
*)
echo "Usage: $0 { start | stop }"
RETVAL=1
;;
esac
exit
But /var/php-nginx/biergaizi.test.php.pid is empty.
What's wrong?
The .pid file is empty, because $! gets substituted by the shell executing your script, instead of the shell executing the commands you pass through su. And as there is no recently started background command in your script, it substitutes an empty string. So, shell started by su executes simply echo > /var/php-nginx/biergaizi.test.php.pid.
To prevent that, quote your command passed to su using single quotes, instead of double quotes. It is better to do that to the "stop" command as well. Like this:
su biergaizi -c 'PHPRC=/home/biergaizi/etc/php5 PHP_FCGI_CHILDREN=2
/usr/bin/php-loop.pl /usr/bin/php-cgi -b /var/run/virtualhost/php5-fpm-biergaizi.test.sock >>/home/biergaizi/logs/php.log 2>&1 </dev/null &
echo $! > /var/php-nginx/biergaizi.test.php.pid'
And this:
su biergaizi -c 'kill `cat /var/php-nginx/biergaizi.test.php.pid` ; sleep 1'
See http://www.gnu.org/software/bash/manual/html_node/Quoting.html for details.
try this:
Escape $ from $!, before passing to su -c.

Resources