Eric Jensen Eric Jensen - 6 months ago 14
Bash Question

bash: differing newline count when assigning result to variable

let's say I want to see how many copies of a program are already running. I could do something like this:

ps ax | grep -c "$0"


that command by itself produces the expected result. BUT if I attempt to assign the output to a variable, it gets incremented by one! No matter how I try it:

var=$(ps ax | grep "$0" | sed -n '$=')
var=`ps ax | grep -c "$0"`


can someone please show me the right way to capture the correct output?

it would also be great to know why this is happening..

UPDATE
after the first response from @fedorqui I realize I wasn't clear enough. let me elaborate:

I am running all three commands above in the same bash script. When I run the first one, it prints out the number 2: the program itself and the grep process with that program as an argument. when I run those same commands within variable assignments, the number 3 is stored.

please note that I am using two different methods of counting lines, grep and sed. in both cases they return 3 instead of the correct answer, 2.

here is a consolidated example to try in a test.sh file:

echo -n "without assignment: "
ps ax | grep -c "$0"
var=$(ps ax | grep "$0" | sed -n '$=')
echo "using sed method: $var"
var=`ps ax | grep -c "$0"`
echo "using grep method: $var"


the results on my debian box:

without assignment: 2
using sed method: 3
using grep method: 3


the questions again: why is this happening, and how to prevent or work around?

Answer
  • Command substitution itself runs in a subshell so thats one bash process

  • your search for bash ($0) i.e. grep -c bash also ends up in the process table at that time so thats another process (grep) containing string bash. Note that, this might not show up in the process table at the time of running, depending on how busy your system is.

  • And you have two (or whatever) actual bash processes (sessions) running presumably are the rest

You can use a Regex trick to get rid of the false positive i.e. grep one from count:

ps ax | grep -c "[b]ash"

It would still count the subshell while doing command substitution:

var=$(ps ax | grep -c "[b]ash")

So you need to manually remove one from this count.

Example:

$ var=$(ps ax | grep -c "bash")    
$ echo $var
4

$ var=$(ps ax | grep -c "[b]ash")   
$ echo $var
3