I have simple unix shell script as follows. Which is giving different count for a service
#!/bin/bash
service=$1
ps -ef | grep $service | grep -v "grep" | wc -l
PROCESS_NUM=$(ps -ef | grep $service | grep -v "grep"| wc -l)
echo $PROCESS_NUM
In the above code below line gives output of 2.
ps -ef | grep $service | grep -v "grep" | wc -l
But when same line is assigned to variable as code below its giving output as 3.
PROCESS_NUM=$(ps -ef | grep $service | grep -v "grep"| wc -l)
echo $PROCESS_NUM
Why this is getting increased by 1 and how to tackle it.
You can see what is happening if the script tees the output to a file before counting the lines and then displaying the output after:
#!/bin/bash
service=$1
echo Directly in Script:
ps -ef | grep $service | grep -v grep | tee test.txt | wc -l
cat test.txt
echo Inside Subshell:
RESULT=$(ps -ef | grep $service | grep -v grep | tee test.txt | wc -l)
echo $RESULT
cat test.txt
When the output of a command is captured, bash starts another shell to run the command - but that subshell also shows up in the process list.
When I run that script I get:
$ ./test.sh lca
Directly in Script:
2
gcti 4268 1 0 2018 ? 21:59:03 ./lca 4999
t816826 9159 7009 0 09:22 pts/1 00:00:00 /bin/bash ./test.sh lca
Inside Subshell:
3
gcti 4268 1 0 2018 ? 21:59:03 ./lca 4999
t816826 9159 7009 0 09:22 pts/1 00:00:00 /bin/bash ./test.sh lca
t816826 9166 9159 0 09:22 pts/1 00:00:00 /bin/bash ./test.sh lca
Related
I want my script to check if it's already running in another instance:
$ cat test.sh
#!/bin/bash
ps -ef | grep -v grep | grep -i "test.sh" | grep bash
ps -ef | grep -v grep | grep -i "test.sh" | grep -c bash
if [ `ps -ef | grep -v grep | grep -i "test.sh" | grep -c bash` -gt 1 ]; then echo "There's another instance running."
else echo "Only this instance is running."
fi
However the output is
$ ./test.sh
noes 9503 7494 0 09:32 pts/1 00:00:00 /bin/bash ./test.sh
1
There's another instance running.
Clearly, 1 is not greater than 1, so why is the if condition triggered?
Thanks
From test man page:
INTEGER1 -gt INTEGER2
INTEGER1 is greater than INTEGER2
So the answer is no, -gt is not triggered when values are equal. In fact, as you can see if you modify the script in this way:
$ cat test.sh
#!/bin/bash
ps -ef | grep -v grep | grep -i "test.sh" | grep bash
ps -ef | grep -v grep | grep -i "test.sh" | grep -c bash
STRINGS=`ps -ef | grep -v grep | grep -i "test.sh"`
echo "$STRINGS"
COUNT=`ps -ef | grep -v grep | grep -i "test.sh" | grep -c bash`
echo $COUNT
if [ `ps -ef | grep -v grep | grep -i "test.sh" | grep -c bash` -gt 1 ]; then echo "There's another instance running."
else echo "Only this instance is running."
fi
You get this:
$ ./test.sh
lucio 5097 4736 0 10:10 pts/2 00:00:00 /bin/bash ./test.sh
1
lucio 5097 4736 0 10:10 pts/2 00:00:00 /bin/bash ./test.sh
lucio 5106 5097 0 10:10 pts/2 00:00:00 /bin/bash ./test.sh
2
There's another instance running.
If you modify the script in this way, it will work:
#!/bin/bash
ps -ef | grep -v grep | grep -i "test.sh" | grep bash
pgrep -c test.sh
if [ $(pgrep -c test.sh) -gt 1 ]; then
echo "There's another instance running."
else
echo "Only this instance is running."
fi
This is the output:
$ ./test.sh
lucio 5197 4736 0 10:17 pts/2 00:00:00 /bin/bash ./test.sh
1
Only this instance is running.
Note the use $() instead of backticks. Check this answer for this change.
I have a small script to check if a service is running in bash
#!/bin/bash
countlines=""$(ps -ef | grep netdata | grep -v grep | wc -l)
echo $countlines >> mylog.log
if [ ${countlines} -lt 3 ];then
sudo /bin/systemctl restart netdata
fi
The problem is when I issue a ps -ef | grep netdata | grep -v grep | wc -l at the command line the result is always 3 but mylog.log is:
6
[update: added filtered ps -ef results]
forge#reportserver:~ ps -ef | grep netdata
netdata 22308 1 0 08:38 ? 00:00:37 /usr/sbin/netdata -D
netdata 22386 22308 0 08:38 ? 00:00:58 /usr/libexec/netdata/plugins.d/apps.plugin 1
netdata 47045 22308 0 11:38 ? 00:00:02 bash /usr/libexec/netdata/plugins.d/tc-qos-helper.sh 1
forge 52028 27902 0 12:34 pts/8 00:00:00 grep --color=auto netdata
why such a discordance?
split into 2 commands to see why:
ps_grep_output=$(ps -ef | grep netdata | grep -v grep)
echo "$ps_grep_output" >> mylog.log
countlines=$(wc -l <<< "$ps_grep_output")
echo "$countlines" >> mylog.log
I keep getting unary operator expected. It seems PRC is not being assigned the value.
PRC=`ps -ef | grep test | wc -l`
if [ ${PRC} -eq 1 ]
then
echo "Congrats"
Note that ps -ef | grep test will usually include the grep process in the output, which you probably don't want. A "clever trick" to avoid this is to match for the string "test" with a regular expression that is not the simple string "test":
$ ps -ef | grep test
jackman 27787 24572 0 09:53 pts/2 00:00:00 grep --color=auto test
$ ps -ef | grep test | wc -l
1
versus
$ ps -ef | grep '[t]est'
(no output)
$ ps -ef | grep '[t]est' | wc -l
0
I do this often enough that I wrote this bash function psg (for "ps grep"):
psg () {
local -a patterns=()
(( $# == 0 )) && set -- $USER # no arguments? vanity search
for arg do
patterns+=("-e" "[${arg:0:1}]${arg:1}")
done
ps -ef | grep "${patterns[#]}"
}
You could also just use
pgrep -f test
Don't forget your closing "fi":
PRC=`ps -ef | grep test| wc -l`
if [ "${PRC}" -eq 1 ]
then
echo "Congrats"
fi
You didn't mention what shell, but this works in bash.
Save a process by using the -c (count) option to grep:
PRC=`ps -ef | grep -c test`
Be advised your pipeline includes in the count the grep command itself, so as you mentioned in your comment above your count is most likely misleading as it is only counting itself. Instead, use this:
PRC=`ps -ef | grep -c [t]est`
This will match commands with "test" in them but not the grep command itself. This is because this is using a regular expression that matches a word starting with a "t". Your command starts with a square bracket so it won't match itself. Resist doing a "grep test | grep -v grep" which is sloppy and just unnecessarily uses a process.
The script:
#!/bin/bash
SERVICE="$1"
RESULT=`ps -a | sed -n /${SERVICE}/p`
MEM=$(ps aux | sort -rk +4 | grep $1 | grep -v grep | awk '{print $4}' | awk 'NR == 1')
if [ "${RESULT:-null}" = null ]; then
echo "$1 is NOT running"
else
echo "$MEM"
fi
if [ "$MEM" -ge 1 ]; then
mailx -s "Alert: server needs to be checked" me#admins.com
fi
The problem with the ps output piped to sed is even if no process is running it finds itself:
ps aux | sed -n /nfdump/p
root 30724 0.0 0.0 105252 884 pts/1 S+ 14:16 0:00 sed -n /process/p
and them my script bypasses the expected result of "service is not running" and goes straight to echo'ing $MEM, which in this case will be 0.0. Does sed have a grep -v grep eqivalent to get itself out of the way?
Let me add one more example in addition to my comments above. Sed has indeed an equivalent to grep -v: You can negate a match with /RE/! (append a ! to the regex) thus you can try:
ps aux | sed -n '/sed/!{ /nfdump/ p;}'
Here the part inside { ... } is only applied to lines not matching sed.
For the record: there is a command pgrep that can replace your ps sed pipeline, see pgrep in Wikipedia or its manpage.
Try :
ps aux | sed -n '/[n]fdump/p'
or :
ps aux | grep '[n]fdump'
The regex won't be find in the processes list
I am writing a bash command that sums the number of services running on specified ports. In my case 4092, 4903, 4904, 4905. Below is my command:
ps -ef | grep '4905\|4904\|4903\|4902' | wc -l
OUTPUT: 5
Here "\|" serves as OR operator. Now the result of this is 5, since it greps the command itself. How can I subtract 1 from the answer so that the output is 4.
Use:
ps -ef | grep '4905\|4904\|4903\|4902' | wc -l | awk '{print $0-1}'
You can remove the last line that contains the result itself before you print number of matches:
ps -ef | grep '4905\|4904\|4903\|4902' | head -n -1 | wc -l
you can save the wc and use awk to get the expected number
ps -ef|grep ...|awk 'END{print NR-1}'