i have some Watcher.sh script running on a directory /foo/bar. When something happens in /foo/bar it starts another script (Updater.sh) which first sleeps for 30 seconds and then do stuff. The Watcher.sh script is managed by supervisor, which is configured to restart the script if it ends. So when there was a change in /foo/bar and the Updater.sh is started (in a subprocess), the Watcher script should end and get started again by supervisor. If there is a second change in /foo/bar the new Updater.sh script should end the first one and start again its 30 second sleep before doing stuff.
Watcher.sh script:
#!/usr/bin/env bash
echo "Started inotifywait with $BASHPID ID"
inotifywait -q -e modify,move,create,delete /foo/bar
/updater.sh &
Updater.sh script:
#!/usr/bin/env bash
echo "Start Update process $BASHPID"
FILE=/var/run/updater.pid
if test -f "$FILE" ; then
kill -9 `cat /var/run/updater.pid`
rm /var/run/updater.pid
fi
echo $BASHPID > /var/run/updater.pid
echo "Change in /foo/bar, reload soon"
sleep 30
supervisorctl reload
My problem is that it just don't happen. The Watcher.sh script is restarted, but the Updater.sh script is not killed at all. I checked the /var/run/updater.pid which is definitely set after the first change, but it just don't enter the if case and even when it does, it does not continue after the kill.
Would be great if somebody knows where i do something wrong, it should be simple right?..
EDIT 1:
Use the following code in the updater.sh to not listen on a pid file
if ps -ef | grep -vE "grep|$BASHPID" | grep updater | awk '{print $2}' ; then
echo "Kill it"
kill -9 `ps -ef | grep -vE "grep|$BASHPID" | grep updater | awk '{print $2}'`
fi
Related
Hello I am trying to write a script to restart other script from command line.
usage should be:
restart someotherscript.sh
cat restart
#!/bin/bash
for pids in $(ps -ef | grep $1 | grep -v grep | awk '{print $2}')
do
kill -9 $pids
done
echo test
sleep 10
$1 &
output is:
root#xxxx:/scripts# restart pricealert.sh
Killed
root#xxxx:
My restart script is killing itself.
What is wrong here? Can you please help me?
Your script is finding itself in the search results because the command you used to start the script contains the script name you're trying to kill.
You can add an if statement to fix this ($$ is the pid of the running script):
if [ "$$" != "$pids" ]; then
kill -9 $pids
fi
I write a mac application. I call a shell script to do some tasks in my mac app. when shell script tasks complete, I want to kill my mac app and reopen it.
I can pgrep [app_name] | xargs kill -9 in shell script. but it does not work.
When I execute this command in my terminal it works. How can I kill my mac app in my shell script ? Hope you can help.
Try doing:
/usr/bin/pkill -9 <app name>
Failing that, and if the app spawns multiple prcesses:
for PID in $(/usr/bin/pgrep <app name>); do /bin/kill -9 $PID; done
If the process is running as root, you'll need to run the script as root or with sudo.
If you're still struggling do the following to help you debug:
#!/bin/bash
APP='<appname>'
LOG= ~/debugkill.log
PIDS: `/usr/bin/pgrep $APP`
echo -e "`/bin/date`: Script running as user: `/usr/bin/whoami` \n
Process to be killed owned by: `ps u $APP | /usr/bin/awk { print $1 }'`" >> $LOG
echo -e "PIDs to terminate: $PIDS >> $LOG
echo -e "Killing PIDs..."
for PID in $PIDS; do
/bin/kill -9 $PID
if [[ `ps $PID | grep $PID | grep -v grep | awk '{ print $1 }'` == "$PID" ]]; then
echo 'killing with sudo (requires pass)'
sudo /bin/kill -9 $PID
fi
if [[ `ps $PID | grep $PID | grep -v grep | awk '{ print $1 }'` == "$PID" ]]; then
echo 'killing with killall -9'
/usr/bin/killall -9 $APP
fi
done >> $LOG
I've had issues before with not being killed from scripts and it turned out that the binary paths weren't specified explicitly for either pkill or kill - and because they are in different folders sometimes one works and the other doesn't depending on which environmental variables are at play when running it.
To relaunch your app, you need to be clear on what app it is, whether it's launched by a binary or launched by java or something, and whether any config parameters are specified when you check the process for it whilst running i.e. run 'ps ax ' and see if anything is running
like so:
/usr/sbin/xinetd -dontfork -pidfile /var/run/xinetd.pid
..as when you relaunch you will need to include the same so you'd do something like this in the script:
/usr/sbin/xinetd -dontfork -pidfile /var/run/xinetd.pid > /dev/null 2>&1
..the other option is to turn the app into a daemon via launchd and then you can simply stop and restart\stop\start the process:
http://blog.frd.mn/how-to-set-up-proper-startstop-services-ubuntu-debian-mac-windows/
I have been trying to find and kill any stale process left after the stop in a ksh script on a linux machine and it doesnt seem to work. It works from the command line but in the script though
here is the code
echo "kill any process still running"
ps -ef | grep qpasa |grep -v grep | awk '{print $2}' |xargs kill
and here is the output from the script log
usage: kill [ -s signal | -p ] [ -a ] pid ...
kill -l [ signal ]
can you you please let me know what am I doing wrong here
I think you call the script when no processes are running. Try kill without arguments and you get the same message.
You can redirect the error to /dev/null but I would try something else:
ps -ef | grep qpasa |grep -v grep | awk '{print $2}' | while read pid; do
echo "Killing ${pid}"
kill ${pid}
sleep 2
kill -9 ${pid} 2>/dev/null
done
The first kill gives qpasa the possibility to the stop controlled: Flush caches and close handles. Give qpasa 2 seconds for it.
When qpasa ignores the signal, kill it the hard way. Of course the process could have stopped already, so this time we want to ignore error messages.
When you have a lot of qpasa processes, you want to sleep 2 seconds only once.
First loop through all processes with a friendly kill, wait 5 seconds, and than hard kill the processes you find. When you make a function kill_qpasa_signal for the looping (and using $1 as kill signal), you can use
kill_qpasa_signal 15
sleep 5
kill_qpasa_signal 9
Does anyone know how to find sidekiq's pidfile to gracefully shut it down?
Running ps ax | grep sidekiq and then running sidekiqctl stop <pid from grep> consistently gives a no such pidfile error?
Cntl-C and Cntl-D also seem to have no effect.
Closing the process window and reopening a new window doesn't kill the process as it appears to be running as a daemon.
The only consistent fix I've found is rebooting.
Use this to kill sidekiq forcefully.
ps -ef | grep sidekiq | grep -v grep | awk '{print $2}' | xargs kill -9
Sidekiq provides the ability to specify a pidfile at start time or, as shown below, to create the pidfile after the process has been started. In either case you can then use the pidfile at stop time.
Use ps -ef | grep sidekiq to find the pid
Create a file (e.g., sidekiq.pid) with the only contents being the pid you just found
sidekiqctl stop <pidfile_name>
Use -P <pidfile_name> or --pidfile <pidfile_name> when starting sidekiq in the future
Just been looking into this one myself...
Seems like newer versions of Sidekiq have this built in:
https://github.com/mperham/sidekiq/wiki/Signals
kill -USR1 [PROCESS_ID]
Worked great for me. The workers stopped picking up new jobs, but finished the ones they were on, then I finally killed the process when it was done.
kill -TERM [PROCESS_ID]
I've written a little handler that can start or stop sidekiq.
start_stop_sidekiq.sh
#!/bin/bash
cmd=$1
PROJECT_DIR=$2
PIDFILE=$PROJECT_DIR/tmp/pids/sidekiq.pid
cd $PROJECT_DIR
start_function(){
LOGFILE=$PROJECT_DIR/log/sidekiq.log
echo "Starting sidekiq..."
bundle exec sidekiq -d -L $LOGFILE -P $PIDFILE -q mailer,5 -q default -e production
}
stop_function(){
if [ ! -f $PIDFILE ]; then
ps -ef | grep sidekiq | grep busy | grep -v grep | awk '{print $2}' > $PIDFILE
fi
bundle exec sidekiqctl stop $PIDFILE
}
case "$cmd" in
start)
start_function
;;
stop)
stop_function
;;
restart)
stop_function && start_function;
;;
*)
echo $"Usage: $0 {start|stop|restart} /path/to/rails/app"
esac
Save it, type chmod +x start_stop_sidekiq.sh.
Then just run it with:
bash start_stop_sidekiq.sh start /path/to/your/rails/app
or
bash start_stop_sidekiq.sh stop /path/to/your/rails/app
If you only have one Rails app, you can also set the $PROJECT_DIR variable statically so that you don't need to specify the path each time. Hope this helps!
Try using god to monitor sidekiq.
Then all you need to do is bundle exec god stop
Alternatively, you can use:
sidekiqctl stop 60
If you like bashes...
scripts/stop_sidekiq.sh
#!/bin/bash
DIR="$( cd "$( dirname "$0" )" && pwd )"
PROJECT_DIR=$DIR/../ # EDIT HERE: rel path to your project form this file location (my scripts are in ./scripts/)
SIDEKIQ_PID_FILE=$PROJECT_DIR/tmp/pids/sidekiq.pid # EDIT HERE: pid file location
if [ ! -f $SIDEKIQ_PID_FILE ]; then
# if no pid file, retrieve pid and create file
ps -ef | grep sidekiq | grep busy | grep -v grep | awk '{print $2}' > $SIDEKIQ_PID_FILE
fi
(cd $PROJECT_DIR && bundle exec sidekiqctl stop $SIDEKIQ_PID_FILE)
Notes:
will work even if sidekiq started without pid file argument
assumes this script is in a folder inside the project and pid files are stored in ./tmp/pids/
Sharing a bash script that checks if sidekiq is running, sends it TSTP to ask it to not pick up any new jobs, waits until any running jobs are finished and then stops the process by sending a TERM signal to it.
https://gist.github.com/kamilbednarz/5ea6398af2a7537aa8feb5a63f3acf2f
Here is my shell script:
#!/bin/bash
PIDS=$(ps -e | grep $1 |grep -v grep| awk '{print $1}')
kill -s SIGINT $PIDS
echo "Done sendings signal"
I am passing the name of the process as command line argument.
The echo command is not getting executed, although the target processes are actually receiving the SIGINT signal and exited.
Any suggestions?
Update:
I changed the code to:
#!/bin/bash
PIDS=$(ps -e |grep $1 | grep -v grep | awk '{print $1}'|grep -v $$)
echo $PIDS
kill -s SIGINT $PIDS
echo "Done sendings signal"
echo "The current process is $$"
Now I am noticing a strange thing:
The script is working but not as expected. Executing following command in command line outside the script
ps -e|grep process-name|grep -v grep|awk '{print $1}'|grep -v $$
gives pid of the process-name but when I execute the same command inside shell script, assign it to variable PIDS and then echo PIDS then it shows one more pid in addition to the pid of process-name. Therefore when the kill command executes it gives an error that the process with second pid doesn't exist. It does echo the remaining sentences in the terminal. Any clue ?
There really are only a couple of possibilities. Assuming you're just running this from the command line, you should see the message ... unless, of course, what you're doing puts the PID of your shell process in PIDS, in which case the kill would kill the (sub) shell running your command before you hit the echo.
Suggestion: echo $PIDS before you call kill and see what's there. In fact, I'd be tempted to comment out the kill and try the command, just to see what happens.
#!/bin/bash
PIDS=$(ps -e | grep $1 |grep -v grep| awk '{print $1}')
echo $PIDS
# kill -s SIGINT $PIDS
echo "Done sendings signal"
Of course, you can always run the script with bash -x to see everything.
Your script works. The only reason I can see for the echo not being executed is that some value of $1 and the script file name combine so that your script PID is also gathered, thereby making the script suicide.
The PIDS line spawns a process running ps, grep, another grep -- so you won't find in PIDS the processes running grep, but what about the parent process itself?
Try:
#!/bin/bash
PIDS=$(ps -e | grep $1 |grep -v grep | awk '{print $1}' | grep -v "^$$\$" )
kill -s SIGINT $PIDS
echo "Done sendings signal"
or run the pipes one after the other with suitable safety greps.
Edit: it is evident that the "$1" selection is selecting too much. So I'd rewrite the script like this:
#!/bin/bash
# Gather the output of "ps -e". This will also gather the PIDs of this
# process and of ps process and its subshell.
PSS=$( ps -e )
# Extract PIDs, excluding this one PID and excluding a process called "ps".
# Don't need to expunge 'grep' since no grep was running when getting PSS.
PIDS=$( echo "$PSS" | grep -v "\<ps\>" | grep "$1" | awk '{print $1}' | grep -v "^$$\$" )
if [ -n "$PIDS" ]; then
kill -s SIGINT $PIDS
else
echo "No process found matching $1"
fi
echo "Done sending signal."
ps -e is identical to ps -A and selects all processes ( cf. http://linux.die.net/man/1/ps ), i. e. ps -e displays "information about other users' processes, including those without controlling terminals" (Mac OS X man page of ps). This means you will also kill the PID ($$) of your shell process, as already pointed out by Charlie Martin, because you will also grep a line of output of the ps -e command that looks like so:
67988 ttys000 0:00.00 /bin/bash ./killpids sleep
Just log the output of ps -e to a file to see that your script commits suicide:
./killpids sleep 2>err.log
#!/bin/bash
# cat killpids
echo $$
for n in {1..10}; do
sleep 5000 &
done
sleep 1
unset PIDS
PIDS="$(ps -e | tee /dev/stderr | grep "$1" | grep -v grep | awk '{print $1}')"
#PIDS="$(ps -www -U $USER -o pid,uid,comm | tee /dev/stderr | grep "$1" | grep -v grep | awk '{print $1}')"
wc -l <<<"$PIDS"
#kill -s SIGINT $PIDS
echo kill -s TERM $PIDS
kill -s TERM $PIDS
echo "Done sendings signal"