Different results between ps aux and `ps aux` inside a script
Why can a single bash script show up multiple times in ps
?
This is typical when any constructs which implicitly create a subshell are in play. For instance, in bash:
echo foo | bar
...creates a new forked copy of the shell to run the echo
, with its own ps
instance. Similarly:
( bar; echo done )
...creates a new subshell, has that subshell run the external command bar
, and then has the subshell perform the echo
.
Similarly:
foo=$(bar)
...creates a subshell for the command substitution, runs bar
in there (potentially exec
'ing the command and consuming the subshell, but this is not guaranteed), and reads its output into the parent.
Now, how does this answer your question? Because
result=$(ps aux | grep | wc)
...runs that ps
command in a subshell, which itself creates an extra bash instance.
How can I properly ensure that only one copy of my script is running?
Use a lockfile.
See for instance:
- How to prevent a script from running simultaneously?
- What is the best way to ensure only one instance of a Bash script is running?
Note that I strongly suggest use of a flock
-based variant.
Ps aux: shows the same script multiple times
Is anything in the while
loop running in the background? It is conceivable that it has the same name as the parent process.
You can check whether some of the processes are subprocesses by running ps wafux
and looking at the process tree.
If they are not "related" to each other, you have very likely simply run the script more than once, and the other processes are not finished yet.
Why if $(ps aux | grep ...) always succeeds in Bash?
Because the grep
process itself is being returned by ps
. You can "trick" grep
to not match itself by surrounding one of the search characters in a character class [ ]
which doesn't change the functionality:
Just do:
if ps aux | grep -q "[b]la bla" ; then echo "found" ; fi
Also, the use of process substitution $()
is unnecessary. The if
will work on the success of the last command in the pipe chain, which is what you want.
Note: The reason the character class trick works is because the ps
output still has the character class brackets but when grep
is processing the search string, it uses the brackets as syntax rather than a fixed string to match.
More elegant ps aux | grep -v grep
The usual technique is this:
ps aux | egrep '[t]erminal'
This will match lines containing terminal
, which egrep '[t]erminal'
does not! It also works on many flavours of Unix.
BASH pass a variable to grep produce different result
In your script:
- You nowhere assign the variable "$n", thus it is empty. Probably you mean to use
n=$2
or just use$2
positional variable instead - "task.log" is useless, if you want it use
tee
to pipe to it - Doing
ps -axu
and then limiting columns withawk
looks strange.ps
can format the output by itself - Parsing
ps | grep
is bad, usepgrep
for that - remember to quote the variables
Your script after some fixing may look like this:
while true; do
cpuusage=$(
pgrep "$2" |
tee >(xargs ps -aux >task.log) |
xargs ps -o cpu% |
awk '{sum += $1} END {print sum}'
)
echo "Total CPU Usage: $cpuusage" >> monitor2.log
sleep "$1"
done
- pgrep is a better alternative to
ps -aux | grep ...
xargs
passespgrep
outupt tops -o %cpu=
ps -o %cpu=
prints percent cpu usage for each processawk
is used to sum it.- Then a simple echo appends to
monitor2.log
file.
Viewing full output of PS command
It is likely that you're using a pager such as less
or most
since the output of ps aux
is longer than a screenful. If so, the following options will cause (or force) long lines to wrap instead of being truncated.
ps aux | less -+S
ps aux | most -w
If you use either of the following commands, lines won't be wrapped but you can use your arrow keys or other movement keys to scroll left and right.
ps aux | less -S # use arrow keys, or Esc-( and Esc-), or Alt-( and Alt-)
ps aux | most # use arrow keys, or < and > (Tab can also be used to scroll right)
Lines are always wrapped for more
and pg
.
When ps aux
is used in a pipe, the w
option is unnecessary since ps
only uses screen width when output is to the terminal.
Related Topics
History Command Works in a Terminal, But Doesn't When Written as a Bash Script
How to Use Grep to Match But Without Printing the Matches
Have One Folder with Files That Have the Same Name But Different File
Stty Serial Port Settings for Parity Not Persistent
Signals and Interrupts a Comparison
Redirecting Tcp-Traffic to a Unix Domain Socket Under Linux
How to Break Up an Extremely Long String Literal in Bash
Expand a Possible Relative Path in Bash
Buffered Asynchronous File I/O on Linux
How to Find the Processor/Chip Architecture on Linux
Why Does '/Proc/Meminfo' Show 32Gb When Aws Instance Has Only 16Gb
How to Use an Older Version of Gcc in Linux
Add Blank Line Between Lines from Different Groups
How to Parse Command Line Options in Bash Shell
How to List One Filename Per Output Line in Linux
Cut or Awk Command to Print First Field of First Row