Finding Process Count in Linux via Command Line

Finding process count in Linux via command line

On systems that have pgrep available, the -c option returns a count of the number of processes that match the given name

pgrep -c command_name

Note that this is a grep-style match, not an exact match, so e.g. pgrep sh will also match bash processes. If you want an exact match, also use the -x option.

If pgrep is not available, you can use ps and wc.

ps -C command_name --no-headers | wc -l

The -C option to ps takes command_name as an argument, and the program prints a table of information about processes whose executable name matches the given command name. This is an exact match, not grep-style. The --no-headers option suppresses the headers of the table, which are normally printed as the first line. With --no-headers, you get one line per process matched. Then wc -l counts and prints the number of lines in its input.

Counting open files per process

Have a look at the /proc/ file system:

ls /proc/$pid/fd/ | wc -l

To do this for all processes, use this:

cd /proc
for pid in [0-9]*
do
echo "PID = $pid with $(ls /proc/$pid/fd/ | wc -l) file descriptors"
done

As a one-liner (filter by appending | grep -v "0 FDs"):

for pid in /proc/[0-9]*; do printf "PID %6d has %4d FDs\n" $(basename $pid) $(ls $pid/fd | wc -l); done

As a one-liner including the command name, sorted by file descriptor count in descending order (limit the results by appending | head -10):

for pid in /proc/[0-9]*; do p=$(basename $pid); printf "%4d FDs for PID %6d; command=%s\n" $(ls $pid/fd | wc -l) $p "$(ps -p $p -o comm=)"; done | sort -nr

Credit to @Boban for this addendum:

You can pipe the output of the script above into the following script to see the ten processes (and their names) which have the most file descriptors open:

  ...
done | sort -rn -k5 | head | while read -r _ _ pid _ fdcount _
do
command=$(ps -o cmd -p "$pid" -hc)
printf "pid = %5d with %4d fds: %s\n" "$pid" "$fdcount" "$command"
done

Here's another approach to list the top-ten processes with the most open fds, probably less readable, so I don't put it in front:

find /proc -maxdepth 1 -type d -name '[0-9]*' \
-exec bash -c "ls {}/fd/ | wc -l | tr '\n' ' '" \; \
-printf "fds (PID = %P), command: " \
-exec bash -c "tr '\0' ' ' < {}/cmdline" \; \
-exec echo \; | sort -rn | head

Count the number of processes and kill them

For maximum portability and reliability, use -A (POSIX synonym of -e) and a custom format with -o rather than -f.

Your filtering of the output of ps is brittle: it may match other processes. You've had to exclude the grep process, and you may need to exclude your script as well, and there may be other completely innocent processes caught in the fray (such as your script itself) because their command line happens to contain $process as a substring. Make your filtering as strict as possible. With ps -o pid= -o comm=, you get just two columns (PID and command without arguments) with no header.

You don't need to use a loop to do the killing, kill accepts multiple arguments. For the counting, let the shell do it: you have a whitespace-separated list of numbers, to let the shell do the word splitting (with $(…) outside quotes) and count the number of resulting words ($#).

count_and_kill_processes () {
set -- $(ps -A -o pid= -o comm= |
awk -v "name=$process" '$2 == name {print $1}')
count=$#
if [ $# -ne 0 ]; then kill "$@"; fi
}
count_and_kill_processes foo
# now the number of killed processes is in $count

If your shell is bash or ksh on all machines, you can use an array.

pids=($(ps -A -o pid= -o comm= |
awk -v "name=$process" '$2 == name {print $1}') )
if [[ $# -ne 0 ]]; then kill "$@"; fi
# the number of killed processes is ${#pids}

How does my Linux C process know how many files were opened on the command line?

There is no way to distinguish between redirections established on the command line and redirections which were already present in the execution environment.

For example, when utility util runs in the script

exec 4<file4
# ...
util 3<file3

it will see both fd 3 and fd 4 open for reading; it can't tell that only one was opened on the command line. If you care about that, which you probably should because there can be a number of these.

That aside, you can certainly figure out which fds are currently open, for example by cycling through all of them or examining the /proc/self/fd pseudo-directory. See this question for some example solutions to finding all the open file descriptors under Linux.

Is there a programmatic way in C to determine the number of processes ever used in a group of processes under Linux?

To enforce the RLIMIT_NPROC limit, linux kernel reads &p->real_cred->user->processes field in copy_process function (on fork() for example)
http://lxr.free-electrons.com/source/kernel/fork.c?v=4.8#L1371

 1371         if (atomic_read(&p->real_cred->user->processes) >=
1372 task_rlimit(p, RLIMIT_NPROC)) {

or in sys_execve (do_execveat_common in fs/exec.c):

1504    if ((current->flags & PF_NPROC_EXCEEDED) &&
1505 atomic_read(¤t_user()->processes) > rlimit(RLIMIT_NPROC)) {
1506 retval = -EAGAIN;
1507 goto out_ret;

So, if the processes is larger than RLIMIT_NPROC, function will fail. This field is defined as part of struct user_struct (accessed with struct cred real_cred in sched.h as

 atomic_t processes;    /* How many processes does this user have? */

So the process count accounting is per-user.

There is decrement of the field in copy_process in case of fail:

1655 bad_fork_cleanup_count:
1656 atomic_dec(&p->cred->user->processes);

And increment of the field is in copy_cred: http://code.metager.de/source/xref/linux/stable/kernel/cred.c#313

313 /*
314 * Copy credentials for the new process created by fork()
315 *
316 * We share if we can, but under some circumstances we have to generate a new
317 * set.
318 *
319 * The new process gets the current process's subjective credentials as its
320 * objective and subjective credentials
321 */
322 int copy_creds(struct task_struct *p, unsigned long clone_flags)

339 atomic_inc(&p->cred->user->processes);

372 atomic_inc(&new->user->processes);

man page says that it is per-user limit: http://man7.org/linux/man-pages/man2/setrlimit.2.html

   RLIMIT_NPROC
The maximum number of processes (or, more precisely on Linux,
threads) that can be created for the real user ID of the
calling process. Upon encountering this limit, fork(2) fails
with the error EAGAIN.


Related Topics



Leave a reply



Submit