Different output when running command in bash script vs terminal - bash

When I run the following code in a bash script I receive an output of 2
#!/bin/bash
HIPPO=$(ps -a | grep hippo | wc -l)
echo "$HIPPO"
However when I run the command ps -a | grep hippo | wc -l straight from a command prompt I get an output of 0
Reading the documentation on ps particularly the -a flag, I'm not understanding why the output is different.

How is called your script? If you named it with hippo, it will count in your ps call.

https://superuser.com/questions/935374/difference-between-and-in-shell-script
When you do the command substitution, the command gets runs once according to the above. So I am assuming, the echo is picking a zombie process that ran that command.

Related

How to find the number of instances of current script running in bash?

I have the below code to find out the number of instances of current script running that is running with same arg1. But looks like the script creates a subshell and executes this command which also shows up in output. What would be the better approach to find the number of instances of running script ?
$cat test.sh
#!/bin/bash
num_inst=`ps -ef | grep $0 | grep $1 | wc -l`
echo $num_inst
$ps aux | grep test.sh | grep arg1 | grep -v grep | wc -l
0
$./test.sh arg1 arg2
3
$
I am looking for a solution that matches all running instance of ./test.sh arg1 arg2 not the one with ./test.sh arg10 arg20
The reason this creates a subshell is that there's a pipeline inside the command substitution. If you run ps -ef alone in a command substitution, and then separately process the output from that, you can avoid this problem:
#!/bin/bash
all_processes=$(ps -ef)
num_inst=$(echo "$all_processes" | grep "$0" | grep -c "$1")
echo "$num_inst"
I also did a bit of cleanup on the script: double-quote all variable references to avoid weird parsing, used $() instead of backticks, and replaced grep ... | wc -l with grep -c.
You might also replace the echo "$all_processes" | ... with ... <<<"$all_processes" and maybe the two greps with a single grep -c "$0 $1":
...
num_inst=$(grep -c "$0 $1" <<<"$all_processes")
...
Modify your script like this:
#!/bin/bash
ps -ef | grep $0 | wc -l
No need to store the value in a variable, the result is printed to standard out anyway.
Now why do you get 3?
When you run a command within back ticks (fyi you should use syntax num_inst=$( COMMAND ) and not back ticks), it creates a new sub-shell to run COMMAND, then assigns the stdout text to the variable. So if you remove the use of $(), you will get your expected value of 2.
To convince yourself of that, remove the | wc -l, you will see that num_inst has 3 processes, not 2. The third one exists only for the execution of COMMAND.

Shell script returning non zero value after killing process

I am trying to kill a process using a shell script.Looks shell itself is getting killed in this process. Also I am seeing non zero return value of the script in terminal.
I am running it on Amazon Linux 2 with sudo.
#!/bin/bash
kill -9 $(ps -ef | grep myapp | grep -v grep | awk '{print $2}')
I am executing like:
sudo ./myscript.sh
"echo $?" after executing is returning 137 instead of zero. Can someone please help to understand what is going wrong.
Another observation:
if i directly run kill command in my terminal, i.e below command,
kill -9 $(ps -ef | grep myapp | grep -v grep | awk '{print $2}')
I see echo $? is returning zero.
Update:
Problem is solved. Name of process I am trying to kill is overlapping with name of my script. Hence grep is returning both the pid's. Both the process are getting killed. Also learnt that better way of doing this by using pkill or using pidof() to get pid.
If you want the exit code of your last-run command to be the exit code for the script, your script must end with exit $? as the last line. Any function before that must also end with the $? so the chain flows to that final line. Otherwise some other exit is taking place.
If the script is being killed along side the application or script you are trying to kill, then your ps and grep work is likely including both in the results. Look at the output of the ps and grep while the script is running. You could add a line prior to your kill line which just shows the output of the ps and greps so you can see what is actually getting killed.
Finally (and I don't think this is the case) if you are trying to end the script after the kill, manually run an exit (again likely using exit $? for the reason stated above) where appropriate within the script.
Hope that helps you get where you are going.

Bash - Two processes for one script

I have a shell script, named test.sh :
#!/bin/bash
echo "start"
ps xc | grep test.sh | grep -v grep | wc -l
vartest=`ps xc | grep test.sh | grep -v grep | wc -l `
echo $vartest
echo "end"
The output result is :
start
1
2
end
So my question is, why are there two test.sh processes running when I call ps using `` (the same happens with $()) and not when I call ps directly?
How can I get the desired result (1)?
When you start a subshell, as with the backticks, bash forks itself, then executes the command you wanted to run. You then also run a pipeline which causes all of those to be run in their own subshells, so you end up with the "extra" copy of the script that's waiting for the pipeline to finish so it can gather up the output and return that to the original script.
We'll do a little expermiment using (...) to run processes explicitly in subshells and using the pgrep command which does ps | grep "name" | grep -v grep for us, just showing us the processes that match our string:
echo "Start"
(pgrep test.sh)
(pgrep test.sh) | wc -l
(pgrep test.sh | wc -l)
echo "end"
which on a run for me produces the output:
Start
30885
1
2
end
So we can see that running pgrep test.sh in a subshell only finds the single instance of test.sh, even when that subshell is part of a pipeline itself. However, if the subshell contains a pipeline then we get the forked copy of the script waiting for the pipeline to finish

Monit losing bash variable?

Trying to get monit to monitor a custom daemon we wrote, and it's just not working with the bash stop/start script. If I run the stop/start script by hand from the command line it's working 100% perfectly, every single time. If it get's executed through monit, the variables is empty. Extract from the script where I am having problems:
GETPID=$(ps aux | grep unicorn | grep master | cut -d" " -f7)
echo "getPID : $GETPID"
echo $GETPID > $PIDFILE
The $GETPID variable is blank when this gets executed with monit. By hand it works perfectly.
Anyone have any ideas?
In general it is not a very good idea to parse the output of ps or ls.
You can write a simple pgrep using find on the proc filesystem:
# find /proc/ -maxdepth 2 -type l -name exe -lname '/bin/bash' -printf '%h\n' 2>/dev/null | sed 's/.*\///'
3580
3595
9504
9869
10054
10156
10193
# pgrep bash
3580
3595
9504
9869
10054
10156
10193
Thanks for the help. Problem was path to unicorn in rvm install.

BASH Command save to variable with a variable in the command

I have a command I want to run first I ran another command to get a directory which is saved in a variable:
path_white="/sys/block/sdb"
Then I want to run another command using this variable and store the output in a variable. I get errors and don't know what I am doing wrong. Any help will be appreciated.
path_pci_white=$(ll $path_white | xargs | cut -d / -f 8 | cut -b 6-13)
it seems that it is not running the entire command below is the error
/sys/block/sdb : is a directory
when i run
ll /sys/block/sdb | xargs | cut -d / -f 8 | cut -b 6-13
in the terminal i get what i want output I just want to use a variable and put the output into a variable
Thanks
ll is an alias for ls -l, and aliases aren't defined in shell scripts. Use an explicit ls -l instead.
There should not be a pipe after xargs. xargs takes as arguments the command it will run. Otherwise there is no point to it.

Resources