The Linux ps command shows different memory usages like RSS (resident set size), size in kB by default. Is there a way to show in MB or GB, like ls -s --human-readable does?
3 Answers
AFAIK you cannot achieve it simply by pure ps command with options. However you can use some text processors like awk and make it to do what you want:
ps afu | awk 'NR>1 {$5=int($5/1024)"M";}{ print;}' This takes result from ps and then for every line except the first one it replacecs 5th column which is in KB normally, to MB adding M suffix.
You can make it an alias and store it in .bashrc file so you can call it by something like myps.
Most of people are asking how to preserve format or use other units and precision.
For simple version you can use column -t output filter:
ps afu | awk 'NR>1 {$5=int($5/1024)"M";}{ print;}' | column -t This however does not recognize spaces in last column correctly. Unfortunately we've got to deal with text formatting and prepare our own format string in printf -like format.
ps afu | awk 'NR==1 {o=$0; a=match($0,$11);}; NR>1 {o=$0;$5=int(10*$5/1024)/10"M";}{ printf "%-8s %6s %-5s %-5s %9s %9s %-8s %-4s %-6s %-5s %s\n", $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, substr(o, a);}' Explanation:
NR==1condition is for first line only (header). We are using original ps output to determine where COMMAND is starting:o=$0stores unmodified entire line so we can use it latera=match($0,$11)finds location of 11th field (which should be where COMMAND column is starting in original output)
NR>1is for following lines (data). We are changing 5th field:$5=int(10*$5/1024)/10"M"changes value into Megabytes with one decimal place and adds "M" suffix.- printf displays all fields in column-like flavor:
%-10smeanssfor string,10for 10 characters wide,-for left align%8smeanssfor string,8for 8 characters wide, and because of no-output of this field is right-aligned.
substr(o, a)takes substring of original line (henceostored before) starting from positionacalculated in previous condition, so we can have command output displayed with spaces preserved.
- 7Modified for GB and with 2 decimal places (e.g.
1.23GB):ps aux | awk '{$5=int(100 * $5/1024/1024)/100"GB";}{ print;}'mahemoff– mahemoff2018-12-19 12:45:27 +00:00Commented Dec 19, 2018 at 12:45 - 2is it possible to achieve the same goal preserving the
psformatting? Tabs are completely stripped away withawkChris– Chris2019-08-22 10:24:04 +00:00Commented Aug 22, 2019 at 10:24 - I see you are casting as an int, is it possible to have it decimal like 1.2M ?JavaSheriff– JavaSheriff2019-08-30 20:20:54 +00:00Commented Aug 30, 2019 at 20:20
- Why tabs are missing?Alex78191– Alex781912020-04-03 18:22:06 +00:00Commented Apr 3, 2020 at 18:22
- @Alex78191: Added alternate command for formatting with table-like outputDevilaN– DevilaN2020-04-06 09:30:24 +00:00Commented Apr 6, 2020 at 9:30
I came here looking for a solution to the same problem. It's surprising there isn't yet a better answer for this. I created my own slightly more flexible fix based on this thread and other pages I read on the web.
I to make things more human readable I made an auto ranging function and used that on the vsz and rss fields.
Also, it looks like there IS actually a way to force an arbitrary field separator on ps. Here is how I did it:
I discovered an apparently undocumented trick while playing around with the field descriptors located in the AIX FORMAT DESCRIPTORS sub heading of the ps manpage. It seams that it will include any characters before the % on each output line when you do something like %U for USER or %z for VSZ for example. I wondered what would happen if I tried %%. It showed a % on every line. OK, how about an arbitrary string without spaces? YES!! BUT apparently you HAVE to have %% in the string for things to work predictably. % doesn't get it. Beware that ps will try to parse everything after the % to see if its a valid field descriptor. Because of this, it is probably safest to keep it at the end of the string like this FOOBARBIGSTRINGBLABLA%% to avoid issues.
Now I just needed to come up with a string that has a relatively low chance of being a part of valid data - especially if I use cmd as a field. zzz:::zzz seems highly unlikely. lets just add the extra %% at the end to make it work - zzz:::zzz%% which shows up in the output as zzz:::zzz%.
I process the output with awk which can handle multi-character field separators, telling awk to look for zzz:::zzz% as the field separator.
|head -n20 and |cut -c -250 at the end is to limit the output to 20 lines and cut each line after 250 characters to keep things neat for my terminal. For actual scripting purposes you would likely want to remove these.
EDIT: I added a variable to call out the fact that you can also sort by any field using these examples. The names for the fields can be found in the manpage for ps under the heading STANDARD FORMAT SPECIFIERS
EDIT 2: As requested, I added a more in-depth explanation about how the arbitrary field separator works and my reasoning for choosing the field separator I chose.
EXAMPLE 1
sortbyfield="rss"; fsep="-o zzz:::zzz%% -o"; ps ax o user:16 $fsep pid $fsep pcpu $fsep pmem $fsep vsz $fsep rss $fsep tty $fsep stat $fsep lstart $fsep time:16 $fsep cmd --sort -$sortbyfield | awk 'function setprefix(num){{n_suffix=1; while(num > 1000 && n_suffix < suffixes_len) {num /= 1024; n_suffix++;}; num=int(100*num)/100suffixes[n_suffix]}; return num} BEGIN{suffixes_len=split("kB MB GB TB PB EB ZB",suffixes);FS="zzz:::zzz%";} NR>1 {$5=setprefix($5);$6=setprefix($6); }{ printf "%-16s %6s %-5s %-5s %9s %9s %-8s %-8s %-25s %-18s %s\n", $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11;}' |head -n20 |cut -c -250 OUTPUT: (slightly sanitized example)
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME CMD gdm 1474 0.0 0.3 2.87GB 182.86MB tty1 Sl+ Sat Jun 18 01:31:44 2022 00:34:40 /usr/bin/gnome-shell gdm 1370 0.0 0.0 171.3MB 34.31MB tty1 Sl+ Sat Jun 18 01:31:43 2022 00:01:56 /usr/libexec/Xorg vt1 -displayfd 3 -auth /run/user/42/gdm/Xauthority -background none -noreset -keeptty -verbose 3 gdm 1552 0.0 0.0 686.07MB 20.14MB tty1 Sl+ Sat Jun 18 01:31:46 2022 00:00:40 /usr/libexec/gsd-color gdm 1577 0.0 0.0 870.49MB 19.53MB tty1 Sl+ Sat Jun 18 01:31:46 2022 00:00:01 /usr/libexec/gsd-media-keys gdm 1538 0.0 0.0 531.81MB 18.51MB tty1 Sl+ Sat Jun 18 01:31:46 2022 00:00:00 /usr/libexec/gsd-xsettings gdm 1541 0.0 0.0 539.53MB 18.5MB tty1 Sl+ Sat Jun 18 01:31:46 2022 00:00:04 /usr/libexec/gsd-power gdm 1570 0.0 0.0 458.5MB 18.4MB tty1 Sl+ Sat Jun 18 01:31:46 2022 00:00:00 /usr/libexec/gsd-wacom gdm 1500 0.0 0.0 386.57MB 17.94MB tty1 Sl Sat Jun 18 01:31:45 2022 00:00:00 /usr/libexec/ibus-x11 --kill-daemon gdm 1537 0.0 0.0 386.13MB 17.92MB tty1 Sl+ Sat Jun 18 01:31:46 2022 00:00:00 /usr/libexec/gsd-clipboard EXAMPLE 2
Slightly less verbose version:
sortbyfield="rss"; fsep="-o zzz:::zzz%% -o"; ps ax o user:16 $fsep pid $fsep pcpu $fsep pmem $fsep vsz $fsep rss $fsep tty $fsep stat $fsep lstart $fsep time:16 $fsep comm --sort -$sortbyfield | awk 'function setprefix(num){{n_suffix=1; while(num > 1000 && n_suffix < suffixes_len) {num /= 1024; n_suffix++;}; num=int(100*num)/100suffixes[n_suffix]}; return num} BEGIN{suffixes_len=split("kB MB GB TB PB EB ZB",suffixes);FS="zzz:::zzz%";} NR>1 {$5=setprefix($5);$6=setprefix($6); }{ printf "%-16s %6s %-5s %-5s %9s %9s %-8s %-8s %-25s %-18s %s\n", $1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11;}' |head -n20 |cut -c -250 OUTPUT: (slightly sanitized example)
USER PID %CPU %MEM VSZ RSS TT STAT STARTED TIME COMMAND gdm 1474 0.0 0.3 2.87GB 182.86MB tty1 Sl+ Sat Jun 18 01:31:44 2022 00:34:40 gnome-shell gdm 1370 0.0 0.0 171.3MB 34.31MB tty1 Sl+ Sat Jun 18 01:31:43 2022 00:01:56 Xorg gdm 1552 0.0 0.0 686.07MB 20.14MB tty1 Sl+ Sat Jun 18 01:31:46 2022 00:00:40 gsd-color gdm 1577 0.0 0.0 870.49MB 19.53MB tty1 Sl+ Sat Jun 18 01:31:46 2022 00:00:01 gsd-media-keys gdm 1538 0.0 0.0 531.81MB 18.51MB tty1 Sl+ Sat Jun 18 01:31:46 2022 00:00:00 gsd-xsettings gdm 1541 0.0 0.0 539.53MB 18.5MB tty1 Sl+ Sat Jun 18 01:31:46 2022 00:00:04 gsd-power gdm 1570 0.0 0.0 458.5MB 18.4MB tty1 Sl+ Sat Jun 18 01:31:46 2022 00:00:00 gsd-wacom gdm 1500 0.0 0.0 386.57MB 17.94MB tty1 Sl Sat Jun 18 01:31:45 2022 00:00:00 ibus-x11 gdm 1537 0.0 0.0 386.13MB 17.92MB tty1 Sl+ Sat Jun 18 01:31:46 2022 00:00:00 gsd-clipboard Hopefully this helps someone out there!
- 2(1) We don’t give bonus points for most characters on one line. Please format scripts as multiple lines so as to avoid the need for horizontal scrolling. (2) It seems that you have chosen
zzz::zzzas an arbitrary string, but the%part is special. Please explain how this works. … … … … … … … Please do not respond in comments; edit your answer to make it clearer and more complete.G-Man Says 'Reinstate Monica'– G-Man Says 'Reinstate Monica'2022-09-06 21:55:25 +00:00Commented Sep 6, 2022 at 21:55 - 2I'm not sure how I can break up the code and still have it make sense. Some of the stuff I'm doing is just loooong. What would you suggest?Kronos– Kronos2022-09-06 23:48:15 +00:00Commented Sep 6, 2022 at 23:48
- The first two statements can be on separate lines. The head and cut statements aren't relevant to the question and can just be left out, if really wanting to keep them in, escaping the new line and putting them on another line makes sense. Then define the parameters to ps on a line so that can be split up. Lastly defining awk functions to be called later and doing it as a script is probably best.LovesTha– LovesTha2023-02-01 00:33:51 +00:00Commented Feb 1, 2023 at 0:33
Learning numfmt
You can use numfmt program from GNU coreutils: http://www.gnu.org/software/coreutils/numfmt. Which is classical example of https://en.wikipedia.org/wiki/Filter_(software)#Unix.
Its options are pretty self-explanatory and easily adjustable.
It can slightly break the columns, thanks to @DevilaN for pointing out this can be fixed with column.
You will, however, need to pay an attention to whether your kilobyte contain 1000 bytes or 1024.
Per man page:
UNIT options: <...skipped...> si accept optional single letter suffix: 1K = 1000, 1M = 1000000, ... iec accept optional single letter suffix: 1K = 1024, 1M = 1048576, ... iec-i accept optional two-letter suffix: 1Ki = 1024, 1Mi = 1048576, ... Results you will get may differ from what you'd expect based on, eg., conversions done elsewhere, because of aforementioned distinction between kilobytes and kibibytes, megabytes and mebibytes, rounding and precision. But all of this can be easily adjusted, and eventually numbers will match.
Usage with ps:
Here's usual output.
$ ps xacu --sort -vsz | head | column -t USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND user 24025 0.3 1.0 49424852 210192 ? Sl Apr27 4:35 chromium-browse user 24505 0.0 0.1 49358956 38928 ? Sl Apr27 0:05 chromium-browse user 13229 0.1 0.4 43088284 88224 ? Sl 10:48 0:03 chromium-browse user 5676 0.0 1.1 39008828 229756 ? Sl Apr27 0:41 chromium-browse user 14746 0.0 0.7 38977064 159160 ? Sl Apr27 1:45 chromium-browse user 19752 0.0 0.3 38967148 78532 ? Sl Feb23 7:07 chromium-browse user 19842 0.0 0.5 38952656 109980 ? Sl Feb23 12:39 chromium-browse user 29085 0.0 0.3 38939280 77832 ? Sl Apr27 1:14 chromium-browse user 17643 0.7 1.0 38937272 217604 ? Sl 11:28 0:04 chromium-browse To exactly megabytes:
$ ps xacu --sort -vsz | head | numfmt --invalid=ignore --header=1 --field=5,6 --from-unit=1Ki --to-unit=1Mi --suffix=M | column -t USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND user 24025 0.3 1.0 48267M 206M ? Sl Apr27 4:35 chromium-browse user 24505 0.0 0.1 48203M 39M ? Sl Apr27 0:05 chromium-browse user 13229 0.1 0.4 42079M 87M ? Sl 10:48 0:03 chromium-browse user 5676 0.0 1.1 38095M 225M ? Sl Apr27 0:41 chromium-browse user 14746 0.0 0.7 38064M 156M ? Sl Apr27 1:45 chromium-browse user 19752 0.0 0.3 38054M 77M ? Sl Feb23 7:07 chromium-browse user 19842 0.0 0.5 38040M 108M ? Sl Feb23 12:39 chromium-browse user 29085 0.0 0.3 38027M 77M ? Sl Apr27 1:14 chromium-browse user 17643 0.7 1.0 38025M 213M ? Sl 11:28 0:04 chromium-browse Act as expected for human-readable flag of some utilites:
$ ps xacu --sort -vsz | head | numfmt --invalid=ignore --header=1 --field=5,6 --from-unit=1Ki --to=iec | column -t USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND user 24025 0.3 1.0 48G 206M ? Sl Apr27 4:35 chromium-browse user 24505 0.0 0.1 48G 39M ? Sl Apr27 0:05 chromium-browse user 13229 0.1 0.4 42G 87M ? Sl 10:48 0:03 chromium-browse user 5676 0.0 1.1 38G 225M ? Sl Apr27 0:41 chromium-browse user 14746 0.0 0.7 38G 156M ? Sl Apr27 1:45 chromium-browse user 19752 0.0 0.3 38G 77M ? Sl Feb23 7:07 chromium-browse user 19842 0.0 0.5 38G 108M ? Sl Feb23 12:39 chromium-browse user 29085 0.0 0.3 38G 77M ? Sl Apr27 1:14 chromium-browse user 17643 0.7 1.0 38G 213M ? Sl 11:28 0:04 chromium-browse
man pssuggests to me that there is no such built-in option.