On Tue 21 Feb 2023 at 16:06:48 (+0100), Andreas Leha wrote:
> David Wright <deb...@lionunicorn.co.uk> writes:
> > On Mon 20 Feb 2023 at 10:39:21 (+0100), Andreas Leha wrote:
> >> Greg Wooledge <g...@wooledge.org> writes:
> >> > On Sun, Feb 19, 2023 at 12:04:22PM -0600, David Wright wrote:
> >> >> But even that's not enough
> >> >> because the field width is somewhat variable: try   ps -eo '%c  |  %z  
> >> >> |  %a'
> >> >> (We can still use | to make the problem somewhat more obvious.)
> >> >
> >> > Oh wow.  Yeah, OK, that's not really solvable.
> >> >
> >> > For those who don't want to try to reverse engineer David's conclusion,
> >> > or who don't just happen to stumble upon it with their current process
> >> > list, here's what I'm seeing:
> >> >
> >> > COMMAND          |     VSZ  |  COMMAND
> >> > systemd          |  164140  |  /sbin/init
> >> > kthreadd         |       0  |  [kthreadd]
> >> > rcu_gp           |       0  |  [rcu_gp]
> >> > rcu_par_gp       |       0  |  [rcu_par_gp]
> >> > [...]
> >> > steamwebhelper   |  4631064  |  
> >> > /home/greg/.steam/debian-installation/[...]
> >> > [...]
> >> > chrome_crashpad  |  33567792  |  
> >> > /opt/google/chrome/chrome_crashpad_handler[...]
> >> > [...]
> >> > kworker/3:0-eve  |       0  |  [kworker/3:0-events]
> >> >
> >> > ps appears to guess an initial maximum width for the VSZ field, but
> >> > when a value comes along that exceeds the guessed maximum, it simply
> >> > shoves the field barrier over.  It doesn't even become the new maximum,
> >> > with all of the fields aligning after that.  It's just a one-time shove,
> >> > breaking the current line only.
> >> >
> >> > Therefore, parsing the header line cannot give us enough information to
> >> > insert field separators correctly in body lines after the fact.
> >> 
> >> 
> >> Dear all,
> >> 
> >> Thanks for chiming in.  The example was indeed simplified and I am using
> >> %a which can contain internal whitespace.
> >> 
> >> This is the command I was using previously:
> >> 
> >>   ps -eo '%p|%c|%C' -o "%mem" -o '|%a' --sort=-%cpu

                     ↑↑↑↑↑↑↑↑↑↑↑↑

> >> I now replaced it with
> >> 
> >>   ps -eo '%p %c %C' -o "%mem" -o ' %a' --sort=-%cpu  | sed -E 's/([0-9]+) 
> >> (.+) ([0-9]+.?[0-9]?) ([0-9]+.?[0-9]?) (.+)/\1|\2|\3|\4|\5/'
> >>  
> >> This works, but is of course cumbersome to maintain.
> >> 
> >> Again, thanks for all the comments!
> >
> > I think there are a few too many assumptions in there;
> > in particular, numbers in %a will match patterns designed
> > to match cpu and mem, because you can't prevent sed from
> > being greedy (except with the [^ … … ]+ construction, to
> > restrict what it matches).
> >
> > This version makes a few assumptions as well:
> > . that the new format matches the old one (mine) if the
> >   delimiters given are a single space (like '%p %c %C'),
> >   or stripped (like "%mem" and '%a', but not ' %a').
> > . the short command is always 15 chars wide even if all
> >   the commands in the table are shorter, eg with ps -o.
> > . I don't have any of those new-fangled extra-long PIDs
> >   yet today.
> >
> > It might well break if a CPU or MEM is running at 100%.
> > That's not easily tested here.
> >
> > I've reordered the columns on the first pass, so that the
> > numeric ones (with their limited character set) come first,
> > which means I can use an auxiliary character for
> > correcting the spacing. (The spaces between the columns get
> > comingled with the leading spaces of numbers.) The second
> > pass sorts that out and processes the heading.
> >
> > $ ps -eo '%p %c %C' -o "%mem" -o '%a' --sort=-%cpu | sed -E 's/( *[0-9]+) 
> > (.{15})( +[0-9.]+ +[0-9.]+) (.*$)/\1~\3~\2\4/;' | sed -E 's/([^~]+)~ 
> > ([^~]+)~(.{15})(.*)/\1|\3|\2|\4/;s/^( *PID) (COMMAND        ) 
> > /\1|\2|/;s/%MEM COMMAND/%MEM|COMMAND/;' | less
> > $ 
> >
> > This is the same, except I deliberately chose _ for the auxiliary
> > character, knowing that short commands are stuffed with underscores:
> >
> > $ ps -eo '%p %c %C' -o "%mem" -o '%a' --sort=-%cpu | sed -E 's/( *[0-9]+) 
> > (.{15})( +[0-9.]+ +[0-9.]+) (.*$)/\1_\3_\2\4/;' | sed -E 's/([^_]+)_ 
> > ([^_]+)_(.{15})(.*)/\1|\3|\2|\4/;s/^( *PID) (COMMAND        ) 
> > /\1|\2|/;s/%MEM COMMAND/%MEM|COMMAND/;' | less
> > $ 
> >
> > Examples:
> >
> >     PID|COMMAND        |%CPU %MEM|COMMAND
> >    9798|firefox-esr    | 2.5  5.8|firefox-esr
> >   16143|Isolated Web Co| 1.8  2.2|/usr/lib/firefox-esr/firefox-esr 
> > -contentproc -childID 11 -isForBrowser -prefsLen 47676 -prefMapSize 232307 
> > -jsInitLen 277276 -parentBuildID 20230214011352 -appDir 
> > /usr/lib/firefox-esr/browser 9798 true tab
> >    1242|Xorg           | 1.0  1.4|/usr/lib/xorg/Xorg -nolisten tcp :0 vt1 
> > -keeptty -auth /tmp/serverauth.FxvBp8B7Qn
> > [ … ]
> >       8|mm_percpu_wq   | 0.0  0.0|[mm_percpu_wq]
> >       9|rcu_tasks_rude_| 0.0  0.0|[rcu_tasks_rude_]
> >      10|rcu_tasks_trace| 0.0  0.0|[rcu_tasks_trace]
> >
> > An incestuous one, with -o rather -eo:
> >
> >     PID|COMMAND        |%CPU %MEM|COMMAND
> >    1694|bash           | 0.0  0.1|bash
> >   23486|ps             | 0.0  0.0|ps -o %p %c %C -o %mem -o %a --sort=-%cpu
> >   23487|sed            | 0.0  0.0|sed -E s/( *[0-9]+) (.{15})( +[0-9.]+ 
> > +[0-9.]+) (.*$)/\1~\3~\2\4/;
> >   23488|sed            | 0.0  0.0|sed -E s/([^~]+)~ 
> > ([^~]+)~(.{15})(.*)/\1|\3|\2|\4/;s/^( *PID) (COMMAND        ) 
> > /\1|\2|/;s/%MEM|COMMAND/%MEM|COMMAND/;
> >   23489|less           | 0.0  0.0|less
> >
> Thanks a lot for this!  Really appreaciated.
> 
> I am missing the delimiter between %CPU and
> %MEM, though...

Yes, as it wasn't in the command you were using previously (see ↑ above).

Cheers,
David.

Reply via email to