18

I need to monitor CPU usage by users of two servers' (Ubuntu and CentOS). For example:

user1     5%
user2    10%
...

Is there a tool similar to top or htop that can do that?

3
  • Do you need top to be displayed in real time? Otherwise, you could consider top -u user and redirect the result to a file, and then monitor another user. you would then have a monitor of proc usage for your users at a given interval.
    – Laurent C.
    Mar 20, 2014 at 12:10
  • When you say monitor over what period? Once in a while or continuously?
    – slm
    Mar 20, 2014 at 12:25
  • I'm hoping to be able to monitor users in realtime like top. Mar 20, 2014 at 23:42

1 Answer 1

22

Here is a script to print the total CPU usage for each user currently logged in, showPerUserCPU.sh:

own=$(id -nu)
cpus=$(lscpu | grep "^CPU(s):" | awk '{print $2}')

for user in $(who | awk '{print $1}' | sort -u)
do
    # print other user's CPU usage in parallel but skip own one because
    # spawning many processes will increase our CPU usage significantly
    if [ "$user" = "$own" ]; then continue; fi
    (top -b -n 1 -u "$user" | awk -v user=$user -v CPUS=$cpus 'NR>7 { sum += $9; } END { print user, sum, sum/CPUS; }') &
    # don't spawn too many processes in parallel
    sleep 0.05
done
wait

# print own CPU usage after all spawned processes completed
top -b -n 1 -u "$own" | awk -v user=$own -v CPUS=$cpus 'NR>7 { sum += $9; } END { print user, sum, sum/CPUS; }'

And here is a slightly modified version for printing the CPU usage of all available users (but skipping the ones with a CPU usage of zero), showAllPerUserCPU.sh:

own=$(id -nu)
cpus=$(lscpu | grep "^CPU(s):" | awk '{print $2}')

for user in $(getent passwd | awk -F ":" '{print $1}' | sort -u)
do
    # print other user's CPU usage in parallel but skip own one because
    # spawning many processes will increase our CPU usage significantly
    if [ "$user" = "$own" ]; then continue; fi
    (top -b -n 1 -u "$user" | awk -v user=$user -v CPUS=$cpus 'NR>7 { sum += $9; } END { if (sum > 0.0) print user, sum, sum/CPUS; }') &
    # don't spawn too many processes in parallel
    sleep 0.05
done
wait

# print own CPU usage after all spawned processes completed
top -b -n 1 -u "$own" | awk -v user=$own -v CPUS=$cpus 'NR>7 { sum += $9; } END { print user, sum, sum/CPUS; }'

The first column represents the user name, the second column the aggregated CPU usage and the third column the normalized CPU use according to the number of CPU cores.

There is also a related script for showing the total memory usage for each user: showPerUserMem.sh

For live-monitoring just execute these scripts periodically via the watch command.

For sorting by CPU usage, pipe the output to sort -k2 -nr.

6
  • 1
    why you are mixing bash env variable with script variable means $USER already exists, even all caps variable is env isn't it? Mar 20, 2014 at 12:58
  • I don't think that all uppercase variables must be environment variables. But I agree that overwriting already existing variables is not a very nice style.
    – scai
    Mar 20, 2014 at 13:03
  • 1
    It is generally a bad idea to use UPPERCASE in bash, for the reason that Rahul mentioned. It is even worse when you are using a variable name that already exists as an environmental one (n bash, $USER is your username already, so ut's the same as the id -nu command you are using. I've edited your post to change this.
    – terdon
    Mar 20, 2014 at 14:27
  • Using uppercase variables in shell scripts is surely not a bad idea as nine out of ten scripts in my /etc/init.d/ directory are doing this, too. Overwriting existing environment variables in contrast should be avoided.
    – scai
    Mar 20, 2014 at 15:14
  • 1
    I added a version to include every user, not just the ones currently logged in.
    – scai
    Mar 21, 2014 at 10:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .