bash command substitution issue with subshell - bash

I was trying to prevent a script from being run by more than one user simultaneously and did not want to use commands only available on some OS'es or shells (pgrep, pidof, ...) and bumped into an issue that I am not sure whether it is a bug or not...
Please ignore the specifics I used in my script: the issue is about the command substitution in bash when using ps.
When I run the following (note the shebang in ksh):
#!/bin/ksh
CMD=`basename $0`
echo $CMD
ps -ef | grep "$CMD"
ps -ef | grep "$CMD" | wc -l
RUNS=`ps -ef | grep "$CMD" | wc -l`
echo $RUNS
if [ $RUNS -gt 2 ]; then
echo The script is currently being run by another user.
#exit 1
fi
RUNS=`ps -ef | grep "$CMD"`
echo "$RUNS"
RUNS=`echo "$RUNS" | wc -l`
echo $RUNS
if [ $RUNS -gt 2 ]; then
echo The script is currently being run by another user.
#exit 1
fi
ps -ef | grep "$CMD" | wc -l > lock
RUNS=`cat lock`
echo $RUNS
if [ $RUNS -gt 2 ]; then
echo The script is currently being run by another user.
exit 1
fi
I get this correct output:
testksh.sh7
abriere 19126 5669 0 14:15 pts/21 00:00:00 /bin/ksh ./testksh.sh7
abriere 19129 19126 0 14:15 pts/21 00:00:00 grep testksh.sh7
2
2
abriere 19126 5669 0 14:15 pts/21 00:00:00 /bin/ksh ./testksh.sh7
abriere 19137 19126 0 14:15 pts/21 00:00:00 grep testksh.sh7
2
2
I get this after replacing the shebang for bash and renaming the script accordingly:
testbash.sh7
abriere 5631 5669 0 14:12 pts/21 00:00:00 /bin/bash ./testbash.sh7
abriere 5634 5631 0 14:12 pts/21 00:00:00 grep testbash.sh7
2
3
The script is currently being run by another user.
abriere 5631 5669 0 14:12 pts/21 00:00:00 /bin/bash ./testbash.sh7
abriere 5643 5631 0 14:12 pts/21 00:00:00 /bin/bash ./testbash.sh7
abriere 5645 5643 0 14:12 pts/21 00:00:00 grep testbash.sh7
3
The script is currently being run by another user.
2
Note the extra line in the ps output.
The following line in bash:
RUNS=`ps -ef | grep "$CMD" | wc -l`
does not return the same value as:
ps -ef | grep "$CMD" | wc -l
Ksh does not have this issue.
As you can see, there are workarounds: I use one in the last section of my script.
I ran the scripts on Linux, AIX and SunOS and they gave me the same results; only Cygwin did not, but the ps command does not return the script in either shell.
Is this a bug? Even if bash runs command substitution within a subshell (see question 21331042), I still consider the variable assigned the value of the command substitution should return the same value as the command itself...

Related

Double process in linux script

Can someone help me understand why if I launch my script, it results in two active processes?
$ ps -ef | grep pong
adminus+ 3024 2923 0 10:25 pts/0 00:00:00 /bin/bash ./pong.sh
adminus+ 3029 3024 0 10:25 pts/0 00:00:00 /bin/bash ./pong.sh`
This is my script:
#!/bin/bash
DIR=/var/tmp/ping-pong
if [ -d $DIR ]
then
echo "Directory Exists"
else
mkdir -p $DIR
fi
ping google.it | while read pong; do echo "$(date): $pong" >> $DIR/google-ping-$(date +%d-%m-%Y).txt; done`
thank you

ps -ef | grep * command not working properly

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

Bash if -gt also triggered when values equal?

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.

echo wc result not right in shell script

this is my shell script
#!/bin/sh
echo "===="
echo $1
echo "===="
ps -ef | grep -w $1 | grep -v -e "grep"
echo "===="
echo $(ps -ef | grep -w $1 | grep -v -e "grep" | wc -l)
echo "===="
exit 0
then,i execute the shell script at command line.
./test.sh php-fpm
the result is:
====
php-fpm
====
0 986 984 0 4:43PM ?? 0:05.53 php-fpm
70 988 986 0 4:43PM ?? 0:00.00 php-fpm
70 989 986 0 4:43PM ?? 0:00.00 php-fpm
70 990 986 0 4:43PM ?? 0:00.00 php-fpm
0 984 1 0 4:43PM ttys000 0:00.01 sudo php-fpm
501 4098 827 0 10:24AM ttys001 0:00.00 /bin/sh ./test.sh php-fpm
====
7
====
so,my question is:why last output is 7 not 6?
thanks.
You can use command
ps -C $1 --no-headers
Updated code is
#!/bin/sh
echo "===="
echo $1
echo "===="
ps -C $1 --no-headers
#ps -lfC $1 --no-headers
echo "===="
COUNT=$(ps -C $1 --no-headers | wc -l)
echo $COUNT
echo "===="
exit 0
Run
sh /tmp/test.sh java
O/P
====
java
====
4969 ? 00:01:00 java
6884 ? 00:00:34 java
10200 ? 00:00:18 java
====
3
====

how to see which users are executing a command (Shell Scripting)

I'm wondering if you could help me with this issue.
I need to write a shell script to see if other users are executing a watch command in the same computer in which an x command is beeing executed.
Could you help me guys?
Thanks a lot.
To solve the question is possible to use ps -aux | grep <prgname> as root user.
E.G.: ps -aux | grep firefox executing this command (as root), it returns the following output:
sergio 3252 24.1 6.7 1840936 540264 ? Sl 09:48 123:36 /usr/lib/firefox/firefox
root 23059 0.0 0.0 15944 948 pts/7 S+ 18:20 0:00 grep --color=auto firefox
The last line is the command I've executed!
Using ps a way to solve your problem may be to use a script like the following. I think that is possible to create better solutions, but this seems to run good on my Ubuntu 14.
#!/bin/bash
i=0
search="watch"
tmp=`mktemp`
ps -aux | tr -s ' ' | grep "$search" > $tmp
while read fileline
do
user=`echo $fileline | cut -f1 -d\ `
prg=`echo $fileline | cut -f11 -d\ `
prg=`basename $prg`
if [ $prg == $search ]; then
echo "$user - $prg"
i=`expr $i + 1`
fi
done < $tmp
if [ $i == 0 ]; then
echo User not found
fi
rm $tmp
while [ 1 ]; do
if [ -n "`ssh $hostname pgrep -f 'Pino_special_command'`" ]; then
ssh $hostname "ps -aux | grep watch" | grep -v "grep"
fi
done
Use the pgrep command
pgrep watch

Resources