Linux - NewbieThis Linux forum is for members that are new to Linux.
Just starting out and have a question?
If it is not in the man pages or the how-to's this is the place!
Notices
Welcome to LinuxQuestions.org, a friendly and active Linux Community.
You are currently viewing LQ as a guest. By joining our community you will have the ability to post topics, receive our newsletter, use the advanced search, subscribe to threads and access many other special features. Registration is quick, simple and absolutely free. Join our community today!
Note that registered members see fewer ads, and ContentLink is completely disabled once you log in.
If you have any problems with the registration process or your account login, please contact us. If you need to reset your password, click here.
Having a problem logging in? Please visit this page to clear all LQ-related cookies.
Get a virtual cloud desktop with the Linux distro that you want in less than five minutes with Shells! With over 10 pre-installed distros to choose from, the worry-free installation life is here! Whether you are a digital nomad or just looking for flexibility, Shells can put your Linux machine on the device that you want to use.
Exclusive for LQ members, get up to 45% off per month. Click here for more info.
I've gone through the following script, and added comments describing my interpretation or questions of various lines. Note that these are not normal #comments, but just `my comments to you indicated by backticks`. Thank you
Code:
`use shell command language which in my case is a symlink to bash`
#!/bin/sh
`comments which should follow this specific format`
### BEGIN INIT INFO
# Provides: Test SOAP Simulator
# Required-Start: $local_fs $network $named $time $syslog
# Required-Stop: $local_fs $network $named $time $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Start SOAP Simulator
# Description: Initiate a given PHP file every 5 seconds to simulate a SOAP server.
### END INIT INFO
`define some global variables`
SCRIPT= /usr/local/bin/test_soap
RUNAS=Michael
PIDFILE=/var/run/test_soap.pid
LOGFILE=/var/log/test_soap.log
start() {
`Need a little help on this one`
if [ -f "$PIDFILE" ] && kill -0 $(cat "$PIDFILE"); then
`send 'Service already running' to stdErr? What is with the & symbol`
echo 'Service already running' >&2
`return 1 indicated an error to the switch statement. What ultimately happens to this value?`
return 1
fi
echo 'Starting service…' >&2
`create the local variable CMD for a command which will executes a given script and sends its output to a given file, and also echos the command on the screen? what is with the ! symbol?`
local CMD="$SCRIPT &> \"$LOGFILE\" & echo \$!"
`Using user "Michael", execute the command which will return an integer, and store that integer in the test_soap.pid file`
su -c "$CMD" $RUNAS > "$PIDFILE"
echo 'Service started' >&2
}
stop() {
if [ ! -f "$PIDFILE" ] || ! kill -0 $(cat "$PIDFILE"); then
echo 'Service not running' >&2
return 1
fi
echo 'Stopping service…' >&2
`please help with the kill -15 ... part. rm part is clear`
kill -15 $(cat "$PIDFILE") && rm -f "$PIDFILE"
echo 'Service stopped' >&2
}
status() {
`get info about the process by pid. Is $$ actually a variable name? Where is it defined? Send output to bottemless pit, but still make it available to if/else statement?`
if ps -p $$ > /dev/null
then
echo "$prog is running"
else
echo "$prog is not running"
fi
RETVAL=$?
return $RETVAL
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
stop
start
;;
status)
status
;;
*)
echo "Usage: $0 {start|stop|restart|status}"
esac
I've gone through the following script, and added comments describing my interpretation or questions of various lines. Note that these are not normal #comments, but just `my comments to you indicated by backticks`. Thank you
start() {
`Need a little help on this one`
if [ -f "$PIDFILE" ] && kill -0 $(cat "$PIDFILE"); then
`send 'Service already running' to stdErr? What is with the & symbol`
echo 'Service already running' >&2
>&2 means "Send this output to where the error stream is currently going". echo normally prints to standard output.
Quote:
`return 1 indicated an error to the switch statement. What ultimately happens to this value?`
return 1
fi
It becomes the return value for the script.
Quote:
echo 'Starting service…' >&2
`create the local variable CMD for a command which will executes a given script and sends its output to a given file, and also echos the command on the screen? what is with the ! symbol?`
local CMD="$SCRIPT &> "$LOGFILE" & echo \$!"
$! is a special variable representing the pid of the job that has been launched
Quote:
`please help with the kill -15 ... part. rm part is clear`
kill -15 $(cat "$PIDFILE") && rm -f "$PIDFILE"
echo 'Service stopped' >&2
15 is the signal number for SIGTERM (terminate). You can find the full list in /usr/include/bits/signum.h.
Quote:
status() {
`get info about the process by pid. Is $$ actually a variable name? Where is it defined? Send output to bottemless pit, but still make it available to if/else statement?`
if ps -p $$ > /dev/null
$$ is another of bash's special variables. It represents the script's own pid. You can get a list of them from the bash man page: just go to Special Parameters.
su -c "/usr/local/bin/test_soap &> '/var/log/test_soap.log' & echo \$!" Michael > "/var/run/test_soap.pid"
To confirm, this will create job test_soap as user Michael, send its output to test_soap.log, echo the PID of this recently created job, and send it to test_soap.pid. Correct?
Code:
kill -15 $(cat "$PIDFILE")
The 15 is redundant, correct?
Code:
if [ -f "$PIDFILE" ] && kill -0 $(cat "$PIDFILE"); then
If the file exists and we error checking indicated that it can be killed?
su -c "/usr/local/bin/test_soap &> '/var/log/test_soap.log' & echo \$!" Michael > "/var/run/test_soap.pid"
That doesn't look quite right to me. I think it should be "&& echo", in other words a boolean "and" separating the two commands.
Quote:
To confirm, this will create job test_soap as user Michael, send its output to test_soap.log, echo the PID of this recently created job, and send it to test_soap.pid. Correct?
I think so. But I wouldn't like to testify to it in court! The syntax is a bit too complicated for my knowledge of bash.
Quote:
Code:
kill -15 $(cat "$PIDFILE")
The 15 is redundant, correct?
Yes, I think it is. According to the kill man page, SIGTERM is the default kill signal.
Quote:
Code:
if [ -f "$PIDFILE" ] && kill -0 $(cat "$PIDFILE"); then
If the file exists and we error checking indicated that it can be killed?
If the file exists, it could either be because the process is already running or because the pidfile was not deleted properly when the job last ended. These two situations can be distinguished by sending an empty message to that pid via kill; success means that the process is running and doesn't have to be started.
"echo \$!": Print the PID of the background job that was just created. The backslash is necessary because you want to delay the expansion of "$!" until the command is actually run, not at the time that string is being assigned to the CMD variable.
[EDIT] I don't think that PID is going to be printed correctly, because that string gets parsed again when "$CMD" is passed as an argument to the su command. That probably needs to be
Code:
local CMD="$SCRIPT &> \"$LOGFILE\" & echo \\\$!"
Last edited by rknichols; 04-29-2017 at 08:08 PM.
Reason: Needs more backslashes
if [ -f "$PIDFILE" ] && kill -0 $(cat "$PIDFILE"); then
`send 'Service already running' to stdErr? What is with the & symbol`
echo 'Service already running' >&2
`return 1 indicated an error to the switch statement. What ultimately happens to this value?`
return 1
fi
just to check if both pid number and pid file are present? if yes then echo is running else return 1 for error?
in other words if true (has PID ) and true (has PID-FILE) then don't run script?
off the command line
Code:
userx%slackwhere ⚡ ~ ⚡>
if [ true ] && [ true ] ; then echo "what" ; fi
what
maybe written like this?
Code:
if [ -f "$PIDFILE" ] && [ kill -0 $(cat "$PIDFILE") ] ; then
echo 'Service already running' > /dev/null 2>>/dev/null
# if this is ran off the command line might
# it not be a good idea to send message to term instead of this?
echo " already running bye "
#stop script from running any further.
exit 0
fi
is it really an error just because it is already running?
it also looks like your mixing methods here Boolean operators with conditionals
yours
Code:
if [ ! -f "$PIDFILE" ] || ! kill -0 $(cat "$PIDFILE"); then
echo 'Service not running' >&2
return 1
should be one or the other
Code:
[ test ] && do something if return is 0
[ test ] || do something if return is anything other than 0
# all of these fire if true
if [ condition true ] ; then
do something
fi
#yes even this one is checking for a true statement
if [ ! true ] ; then
do something
fi
# if this or that
if [ something ] || [ something ] ; then
do something
fi
# if both true
if [[ true && true ]] ; then
do something
fi
ect..
[[ ]] and [ ] get interpreted differently as well.
example
off one of my scripts nested Boolean with conditionals
I think most of your answers have been supplied, so I will ask a question ... Did you give us the original init script?
The reason for my question is because it refers to a variable ($prog) which is never assigned and hence will be empty, so your status output will be "is running" or "is not running"
I do have some small input on some of your comments:
use shell command language which in my case is a symlink to bash :- The line in question does not have to do with the shell, it is the interpreter line, hence you can change it to refer to perl (which is not a shell). Also, important note, when referring to bash via the symlink sh actually tells bash to run in POSIX mode, hence certain bash specific constructs will not be available, but makes the overall script
more usable in more environments which might not have bash as the default
comments which should follow this specific format :- more than just the format, the comments you are referring to give specific details about this particular init script
create the local variable CMD for a command which will executes a given script and sends its output to a given file, and also echos the command on the screen? :- just clarifying, it will NOT echo to the screen
Send output to bottemless pit, but still make it available to if/else statement? :- No there are no details being made available to the if/else. The 'if' is a command and checks the return value of the command presented to it (ps in this case)
One last point, whilst the kill commands default may be SIGTERM, the inclusion of the switch '-15' makes it unambiguous. Also, on other systems this may not necessarily be the default action (thinking AIX or Solaris)
Thanks rknichols, Ah, I now see how "&>" does as you say. bash has such a long manual, it is difficult to remember everything. Couple more specific questions regarding this line alone.
Were escaped double quotes required, or can single quotes be used around $LOGFILE?
Does the order of redirecting or the background & make a difference?
Is the backslash to delay expanding $! a bash or echo arguments? I can't find anything on it.
Guess this last one relates to two lines. Are the following two sections the same?
Code:
local CMD="$SCRIPT &> "$LOGFILE" & echo \$!"
su -c "$CMD" $RUNAS > "$PIDFILE"
Code:
local CMD="$SCRIPT &> "$LOGFILE" &"
su -c "$CMD" $RUNAS
echo \$! > "$PIDFILE"
Thanks grail, No, it wasn't quite the original script as I tried to add the status portion. You are correct that $prog isn't defined, and I needed to do so in my original declaration of global variables.
Thanks rknichols, Ah, I now see how "&>" does as you say. bash has such a long manual, it is difficult to remember everything. Couple more specific questions regarding this line alone.
Were escaped double quotes required, or can single quotes be used around $LOGFILE?
Does the order of redirecting or the background & make a difference?
Is the backslash to delay expanding $! a bash or echo arguments? I can't find anything on it.
Guess this last one relates to two lines. Are the following two sections the same?
Code:
local CMD="$SCRIPT &> "$LOGFILE" & echo \$!"
su -c "$CMD" $RUNAS > "$PIDFILE"
Code:
local CMD="$SCRIPT &> "$LOGFILE" &"
su -c "$CMD" $RUNAS
echo \$! > "$PIDFILE"
The escaped double quotes are required. You want those quotes to be present literally in the string assigned to CMD. Quotes do not nest. If you don't escape those interior quotes, what you have are two quoted strings, "$SCRIPT &> " and " & echo \$!" with the unquoted expansion of LOGFILE between them. Really, as long as LOGFILE doesn't contain any characters that need to be quoted, it doesn't matter. But in that case, those escaped double quotes could have been omitted entirely.
That "&" putting the command in the background acts as a command separator, just like ";". I don't think you would be asking if the placement of a ";" was significant.
The backslash escape on "\$!" simply tells bash to take that "$" character literally and not as the start of a parameter expansion. The two-character sequence "$!" will thus be included literally in the CMD string. If you don't do that, the "$!" will be expanded as part of the variable assignment, i.e., to the PID of the last background process (of which there probably was none) started prior to doing the assignment. It's like saying "X=$Y" before assigning any value to Y.
No, they are not the same. In the first, the echo command is part of the string passed to su to be executed under the new UID. In the second, the echo command is run by the current shell under the current UID. Since the backgrounded process is not a direct child of the current shell, a "$!" in the current shell would not expand to its PID.
Note also the addendum to my previous post. There are not enough backslashes in that "\$!" to get it expanded at the proper time. This is the problem with using shell variables to hold command strings. The strings get evaluated multiple times by the shell, and it is very hard to get quoting and escaping to work the way you want. In most cases, shell functions are a much preferable alternative, but that just doesn't work in the context of passing a command string to su for execution.
It is useful to run your script with the shell's "-x" option. That way, you can see how the strings change each time they are parsed and what actually gets passed to each command.
Last edited by rknichols; 04-30-2017 at 10:29 AM.
Reason: minor spelling typo
Yes, I understand quotes cannot be nested. I was talking about 'single quotes' and "escaped double quotes". Granted, I just noticed on my last post, I didn't show it this way, so see how my question was misleading.
Regarding position, I was asking whether "$SCRIPT &> "$LOGFILE" & echo \$!" is different than "$SCRIPT & &> "$LOGFILE" echo \$!"
Thanks
I should have asked if the following are the same:
Code:
local CMD="$SCRIPT &> "$LOGFILE" & echo \$!"
su -c "$CMD" $RUNAS > "$PIDFILE"
Code:
local CMD="$SCRIPT &> "$LOGFILE" &"
su -c "$CMD" $RUNAS
su -c echo \$! $RUNAS > "$PIDFILE"
Yes, I saw your addendum, and will experiment to ensure I get the correct results. Also, thanks for pointing out the shell's "-x" option as it will make testing much easier.
Yes, I understand quotes cannot be nested. I was talking about 'single quotes' and "escaped double quotes". Granted, I just noticed on my last post, I didn't show it this way, so see how my question was misleading.
There is no bit of magic that can make this simple. The string that you write is going to be parsed by a shell 3 times: (1) when the string is assigned to the CMD variable, (2) when the contents of $CMD are expanded and passed to su, and (3) when the entire command is evaluated by the final shell that will execute it. If the value of LOGFILE contains spaces or other characters that are special to the shell, you have to consider what that whole string will look like at each step along the way and how each shell will interpret it. And even the escaped double quotes you have aren't really sufficient. That final shell is still going to see that LOGFILE string unquoted.
Quote:
Regarding position, I was asking whether "$SCRIPT &> "$LOGFILE" & echo \$!" is different than "$SCRIPT & &> "$LOGFILE" echo \$!"
Those are very different. The "&" is a command separator, like <newline> or ";". Ignoring the quoting problems, the first is equivalent to these two command lines
Code:
$SCRIPT &> "$LOGFILE" &
echo \$!
The second is equivalent to
Code:
$SCRIPT &
&> "$LOGFILE" echo \$!"
which runs $SCRIPT in the background without the $LOGFILE redirection and then directs just the echoed PID to $LOGFILE, which is not anything like what you want.
Quote:
I should have asked if the following are the same:
Code:
local CMD="$SCRIPT &> "$LOGFILE" & echo \$!"
su -c "$CMD" $RUNAS > "$PIDFILE"
Code:
local CMD="$SCRIPT &> "$LOGFILE" &"
su -c "$CMD" $RUNAS
su -c echo \$! $RUNAS > "$PIDFILE"
No, that second one is running two separate shells, and the second shell will have no knowledge of the background process launched by the other shell.
Consider the following. Maybe I don't want Michael to have the ability to write to /var/run/ or /var/log/. But as the command is executed by Michael, he needs to have that ability. How can I have my cake and eat it too?
Also, my status doesn't make sense but cause this script will also have a PID when it is being run. What I need to do is test the pid using the value stored in test_soap.pid. I've tried cat'n the value to no success. How is this accomplished?
Thank you for all your help!
Code:
RUNAS=Michael
PIDFILE=/var/run/test_soap.pid
LOGFILE=/var/log/test_soap.log
status() {
#...
local CMD="$SCRIPT &> "$LOGFILE" & echo \$!"
su -c "$CMD" $RUNAS > "$PIDFILE"
#...
}
status() {
if ps -p $$ > /dev/null
then
echo "is running"
else
echo "is not running"
fi
RETVAL=$?
return $RETVAL
}
Consider the following. Maybe I don't want Michael to have the ability to write to /var/run/ or /var/log/. But as the command is executed by Michael, he needs to have that ability. How can I have my cake and eat it too?
You could play games with file descriptors and move the output redirection outside the su command:
That opens $LOGFILE on file descriptor 3 before invoking su, then redirects the command's stdout and stderr to that opened fd3. The redirection onto "$PIDFILE" is already outside the su command. Of course the current user (the one invoking this script) must have write permission in those directories.
Quote:
Also, my status doesn't make sense but cause this script will also have a PID when it is being run. What I need to do is test the pid using the value stored in test_soap.pid. I've tried cat'n the value to no success. How is this accomplished?
Should be simple enough:
Code:
if ps -p $(cat $PIDFILE) >/dev/null; then
Or, a bit simpler
Code:
if [ -d /proc/$(<$PIDFILE) ]; then ...
Note that "$(<$PIDFILE)" is just a convenient shorthand for "$(cat $PIDFILE)" that avoids a "useless use of cat".
Last edited by rknichols; 04-30-2017 at 04:03 PM.
Reason: harmless typos
LinuxQuestions.org is looking for people interested in writing
Editorials, Articles, Reviews, and more. If you'd like to contribute
content, let us know.