I need to check if Tomcat is running in my system via a shell script. If not I need to catch the process id and kill Tomcat. How shall it be achieved?
in order to get the running process, I've used this command:
ps x | grep [full_path_to_tomcat] | grep -v grep | cut -d ' ' -f 1
You have to be careful, though. It works on my setup, but it may not run everywhere... I have two installations of tomcat, one is /usr/local/tomcat on port 8080 and /usr/local/tomcat_8081 on port 8081. I have to use '/usr/local/tomcat/' (with the final slash) as the full_path because otherwise it would return 2 different pids if tomcat_8081 is running as well.
Here's the explanation of what this command does:
1) ps x gives you a list of running processes ordered by pid, tty, stat, time running and command.
2) Applying grep [full_path_to_tomcat] to it will find the pattern [full_path_to_tomcat] within that list. For instance, running ps x | grep /usr/local/tomcat/ might get you the following:
13277 ? Sl 7:13 /usr/local/java/bin/java -Djava.util.logging.config.fil
e=/usr/local/tomcat/conf/logging.properties [...] -Dcatalina.home=/usr/local/tomca
t [...]
21149 pts/0 S+ 0:00 grep /usr/local/tomcat/
3) As we get 2 entries instead of one due to the grep /usr/local/tomcat/ matching the pattern, let's remove it. -v is the invert-match flag for grep, meaning it will select only lines that do not match the pattern. So, in the previous example, using ps -x | grep /usr/local/tomcat/ | grep -v grep will return:
13277 ? Sl 7:13 /usr/local/java/bin/java -Djava.util.logging.config.fil
e=/usr/local/tomcat/conf/logging.properties [...] -Dcatalina.home=/usr/local/tomca
t [...]
4) Cool, now we have the pid we need. Still, we need to strip all the rest. In order to do that, let's use cut. This command removes sections from a FILE or a standard output. The -d option is the delimiter and the -f is the field you need. Great. So we can use a space (' ') as a delimiter, and get the first field, which corresponds to the pid. Running ps x | grep /usr/local/tomcat/ | grep -v grep | cut -d ' ' -f 1 will return:
13277
Which is what you need. To use it in your script, it's simple:
#replace below with your tomcat path
tomcat_path=/users/tomcat/apache-tomcat-8.0.30
pid=$(ps x | grep "${tomcat_path}" | grep -v grep | cut -d ' ' -f 1)
if [ "${pid}" ]; then
eval "kill ${pid}"
fi
One way to check by using wget for your server address and checking the status.
Check this link here :
http://www.velvettools.com/2013/07/shell-script-to-check-tomcat-status-and.html#.VX_jfVz-X1E
TOMCAT_HOME=/usr/local/tomcat-folder/
is_Running ()
{
wget -O - http://yourserver.com/ >& /dev/null
if( test $? -eq 0 ) then
return 0
else
return 1
fi
}
stop_Tomcat ()
{
echo "shutting down......"
$TOMCAT_HOME/bin/shutdown.sh
}
start_Tomcat ()
{
echo "starting......"
$TOMCAT_HOME/bin/startup.sh
}
restart ()
{
stop_Tomcat
sleep 10
kill_Hanged_Processes
start_Tomcat
sleep 60
}
the easy way to do that is :
ps -ef | grep tomcat
by using this command you'll get :
user [id-to-kill] Date [tomcat-path]
last step is killing the process
sudo kill -9 [id-to-kill]
Congratulation, your process was killed lOol
Tomcat's default port is 8080. u can grep it and use port status in comparision loop.
#!/bin/bash
STAT=`netstat -na | grep 8080 | awk '{print $7}'`
if [ "$STAT" = "LISTEN" ]; then
echo "DEFAULT TOMCAT PORT IS LISTENING, SO ITS OK"
elif [ "$STAT" = "" ]; then
echo "8080 PORT IS NOT IN USE SO TOMCAT IS NOT WORKING"
## only if you defined CATALINA_HOME in JAVA ENV ##
cd $CATALINA_HOME/bin
./startup.sh
fi
RESULT=`netstat -na | grep 8080 | awk '{print $7}' | wc -l`
if [ "$RESULT" = 0 ]; then
echo "TOMCAT PORT STILL NOT LISTENING"
elif [ "$RESULT" != 0 ]; then
echo "TOMCAT PORT IS LISTENINS AND SO TOMCAT WORKING"
fi
this way you can compare the script.you grep port 8080 if you are using the default port for tomcat.this will only check whether tomcat is running.
then you can check the processes using the port
lsof -i:8080 //if using port 8080
the if you want to free the port by killing the process using it use this command
kill 75782 //if for instance 75782 is the process using the port
Related
I try to start all the exited docker containers deployed in separated servers, so basically i should execute the essential command below
[ $(docker ps -a | grep Exited | wc -l) -ne 0 ] && docker start $(docker ps -a | grep Exited | cut -d' ' -f1)
It worked fine like in pure linux shell , but then error occured(show below) when i try to use expect to "send" the "essential" command. (local ip is 241,remote end is 209)
[root#localhost start_shell_dir]# spawn ssh root#192.168.1.209
root#192.168.1.209's password:
Last login: Fri Oct 15 22:23:25 2021 from 192.168.1.241
[root#localhost ~]# invalid command name "0"
while executing
"0 -ne 0 "
invoked from within
"send "[ 0 -ne 0 ] && docker start ""
The error log shows i have already log in the remote machine, and something wrong when i execute the docker command.
Glenn jackman from the comment area shows me the basic rule for tcl,then i realize expect does command substitutions before sending real command. We may see it from execute bash -x script.sh .
[root#localhost start_shell_dir]# bash -x startContainer.sh
+ read ip pass
+ read ip pass
+ /usr/bin/expect
[root#localhost start_shell_dir]# ++ docker ps -a
++ grep Exited
++ wc -l
++ docker ps -a
++ grep Exited
++ cut '-d ' -f1
spawn ssh root#192.168.1.209
root#192.168.1.209's password:
Last login: Fri Oct 15 22:37:56 2021 from 192.168.1.241
[root#localhost ~]# invalid command name "0"
while executing
"0 -ne 0 "
invoked from within
"send "[ 0 -ne 0 ] && docker start ""
Anyway, the final command that work for me is the command showed below(replace double quotes with braces and with backslash before $() to keep it as an ordinary character rather than pre-parse it).
send {[ \$(docker ps -a | grep Exited | wc -l) -ne 0 ] && docker start \$(docker ps -a | grep Exited | cut -d' ' -f1)}
#!/bin/bash
# my original script with error
while read ip pass
do
{
/usr/bin/expect <<-END
spawn ssh root#$ip
expect {
"yes/no" { send "yes\r";exp_continue }
"password:" { send "$pass\r" }
}
expect "#"
send "[ $(docker ps -a | grep Exited | wc -l) -ne 0 ] && docker start $(docker ps -a | grep Exited | cut -d' ' -f1)"
expect eof
END
}&
done<apps_ip.txt
Like the shell, Tcl (and expect) allows interpolation with double quotes. Tcl uses square brackets for command substitution (in the same way that the shell uses $(...))
Use curly braces to protect the contents of that string (analogous to the shell's single quotes):
send {[ $(docker ps -a | grep Exited | wc -l) -ne 0 ] && docker start $(docker ps -a | grep Exited | cut -d' ' -f1)}
#....^.............................................................................................................^
# and don't forget to hit Enter
send "\r"
See https://www.tcl-lang.org/man/tcl8.6/TclCmd/Tcl.htm for the few syntax rules of Tcl.
I have a file with many service names, some of them are running, some of them aren't.
foo.service
bar.service
baz.service
I would like to find an efficient way to get the PIDs of the running processes started by the services (for the not running ones a 0, -1 or empty results are valid).
Desired output example:
foo.service:8484
bar.server:
baz.service:9447
(bar.service isn't running).
So far I've managed to do the following: (1)
cat t.txt | xargs -I {} systemctl status {} | grep 'Main PID' \
| awk '{print $3}'
With the following output:
8484
9447
But I can't tell which service every PID belongs to.
(I'm not bound to use xargs, grep or awk.. just looking for the most efficient way).
So far I've managed to do the following: (2)
for f in `cat t.txt`; do
v=`systemctl status $f | grep 'Main PID:'`;
echo "$f:`echo $v | awk '{print \$3}'`";
done;
-- this gives me my desired result. Is it efficient enough?
I ran into similar problem and fount leaner solution:
systemctl show --property MainPID --value $SERVICE
returns just the PID of the service, so your example can be simplified down to
for f in `cat t.txt`; do
echo "$f:`systemctl show --property MainPID --value $f`";
done
You could also do:
while read -r line; do
statuspid="$(sudo service $line status | grep -oP '(?<=(process|pid)\s)[0-9]+')"
appendline=""
[[ -z $statuspid ]] && appendline="${line}:${statuspid}" || appendline="$line"
"$appendline" >> services-pids.txt
done < services.txt
To use within a variable, you could also have an associative array:
declare -A servicearray=()
while read -r line; do
statuspid="$(sudo service $line status | grep -oP '(?<=(process|pid)\s)[0-9]+')"
[[ -z $statuspid ]] && servicearray[$line]="statuspid"
done < services.txt
# Echo output of array to command line
for i in "${!servicearray[#]}"; do # Iterating over the keys of the associative array
# Note key-value syntax
echo "service: $i | pid: ${servicearray[$i]}"
done
Making it more efficient:
To list all processes with their execution commands and PIDs. This may give us more than one PID per command, which might be useful:
ps -eo pid,comm
So:
psidcommand=$(ps -eo pid,comm)
while read -r line; do
# Get all PIDs with the $line prefixed
statuspids=$(echo $psidcommand | grep -oP '[0-9]+(?=\s$line)')
# Note that ${statuspids// /,} replaces space with commas
[[ -z $statuspids ]] && appendline="${line}:${statuspids// /,}" || appendline="$line"
"$appendline" >> services-pids.txt
done < services.txt
OUTPUT:
kworker:5,23,28,33,198,405,513,1247,21171,22004,23749,24055
If you're confident your file has the full name of the process, you can replace the:
grep -oP '[0-9]+(?=\s$line)'
with
grep -oP '[0-9]+(?=\s$line)$' # Note the extra "$" at the end of the regex
to make sure it's an exact match (in the grep without trailing $, line "mys" would match with "mysql"; in the grep with trailing $, it would not, and would only match "mysql").
Building up on Yorik.sar's answer, you first want to get the MainPID of a server like so:
for SERVICE in ...<service names>...
do
MAIN_PID=`systemctl show --property MainPID --value $SERVICE`
if test ${MAIN_PID} != 0
than
ALL_PIDS=`pgrep -g $MAIN_PID`
...
fi
done
So using systemctl gives you the PID of the main process controlled by your daemon. Then the pgrep gives you the daemon and a list of all the PIDs of the processes that daemon started.
Note: if the processes are user processes, you have to use the --user on the systemctl command line for things to work:
MAIN_PID=`systemctl --user show --property MainPID --value $SERVICE`
Now you have the data you are interested in the MAIN_PID and ALL_PIDS variables, so you can print the results like so:
if test -n "${ALL_PID}"
then
echo "${SERVICE}: ${ALL_PIDS}"
fi
Have a slew of services that run as part of a hadoop stack; want a simple CLI script that checks the various processes and gives a simple output for end user.
There will be over 50 hosts; and around 10 services it will need to check on each host.
Currently written in bash; I like the output but the code is slllloooowww as it checks each process; 1 at a time via passwordless ssh and pgrep.
Looking for advice or hints on making this faster.
ie:
Hostname | IP | Ping | SSH | Zookeeper | Namenode | Datanode
localhost | 127.0.0.1 | online | online | _ | _ | _
node1 | 172.30.50.150 | online | online | _ | _ | _
dn1 | 10.142.0.100 | online | online | online | online | online
sample code:
fun_datanode () {
zup=`ssh $1 "ps ax | grep -v grep | grep datanode | wc -l"`
if [ $zup -gt 0 ]; then
dn=online
else
dn="_"
fi
}
#main
#main loop that reads host file
for host in `awk '/^[0-9]/ { print $1 }' /etc/hosts`
do
#ping
fping -c1 -t10 -n $host > /dev/null 2>&1
RETVAL=$?
hname=`getent hosts $host | awk '{print $2 }'`
if [ $RETVAL -eq 0 ]; then
if ssh $host 'pgrep ssh' > /dev/null 2>&1; then
ssh=online
fun_zookeeper $host
fun_namenode $host
fun_datanode $host
fi
fun_print "$hname $host "online" $ssh $zoo $nn $dn"
echo
else
fun_print $hname $host "${red}offline${norm}" "_" "_" "_" "_"
echo
fi
done
You should use Ganglia or Ambari to monitor large clusters. They are free and open source. They have monitoring as well as alerting capabilities based up on thresholds.
There are utilities like pdsh (parallel distributed shell)
https://code.google.com/p/pdsh/wiki/UsingPDSH
This can be used to run process checks in parallel on many nodes.
Parallel SSH was archived (read-only) in Google Code. For more up-to-date releases see https://github.com/pkittenis/parallel-ssh .
Another option is Fabric:
http://www.fabfile.org/
Found a working solution without scope creeping into a major project;
Instead of going to the well each time for getting process status on node via SSH; grab the ps ax once on every node then assign to local variable. Then interrogate the variable each time for current process status.
Instead of doing (amount of nodes X amount of services) = SSH connections; now it only does (amount of nodes) = SSH connections.
From there; I may background / fork each SSH...
fun_grabps () {
psout=`ssh $1 "ps ax"`
}
fun_zookeeper () {
zup=`echo $psout | grep -v grep | grep zoo | wc -l`
if [ $zup -gt 0 ]; then
zoo=online
else
zoo="_"
fi
}
We have a script which is checking and sending an alert if process goes down. For some reason it is not capturing it properly for all the users and not sending the alerts in all scenarios.
Please suggest what could be the problem.
Environments – uatwrk1, uatwrk2, uatwrk3 ------- uatwrk100
ServerName - myuatserver
Process to be checked - Amc/apache/bin/httpd
Script is :
#!/bin/ksh
i=1
while (( i<=100 ))
do
myuser=uatwrk$i
NoOfProcess=`ps -ef | grep -v grep | grep $myuser | grep "Amc/apache/bin/httpd" | wc -l`
if [[ $NoOfProcess -eq 0 ]]
then
echo "Amc process is down, sending an alert"
# Assume sendAlert.ksh is fine
./sendAlert.ksh
else
echo "Amc process is running fine" >> /dev/null
fi
(( i+=1 ))
done
I think #Mahesh already indicated the problem in a comment.
When you only want to have a mail once, you can count the users running a httpd process. The backslash in the following command is for avoiding grep -v grep.
ps -ef | grep "A\mc/apache/bin/httpd" | cut -d " " -f1 | grep "^uatwrk"| sort -u | wc -l
I have this script
#!/bin/bash
npid=$(pgrep -f procname | wc -l)
echo $npid
if [ $npid -lt 3 ];then
service procname start;
fi
When procname is running, it works fine showing the correct number for $npid. It fails when there isn't any procname running. It should return zero, but it returns npid=3, exactly 3. The same problem I see for ps auxw | grep procname | grep -v grep | wc -l as well.
Something trivially wrong I just couldn't figure out, any suggestions ?
* EDIT
# This returns nothing if therisn't a process name poopit running
pgrep -f poopit
# In the case when no process running, below returns zero if typed on a bash cmd line
pgrep -f poopit | wc -l
# If running,
pgrep -f poopit | wc -l
17
# If running, the script $npid shows
19