On Thu, Mar 14, 2019 at 11:14:17PM -0700, Todd Chester via perl6-users wrote:
> > > On Fri, 15 Mar 2019, 05:34 Todd Chester via perl6-users,
> > > <perl6-us...@perl.org <mailto:perl6-us...@perl.org>> wrote:
> > > 
> > > 
> > > 
> > >     On 3/14/19 10:05 PM, Todd Chester via perl6-users wrote:
> > >      > Hi All,
> > >      >
> > >      > What am I doing wrong here?
> > >      >
> > >      > ps ax | grep [f]irefox | perl6 -ne 'my @x =
> > >     $_.words[0].lines.reverse;
> > >      > print @x[0] ~ "\n";'
> > >      > 7380
> > >      > 7581
> > >      > 7698
> > >      > 13023
> > >      > 13767
> > >      > 13908
> > >      >
> > >      >
> > >      > Two problems:
> > >      >
> > >      > 1) "lines" is putting everything into @x[0]
> > >      >
> > >      > 2) "reverse" is ignoring me as there is no @x[1]. etc.
> > >      >
> > >      > The result I want is 13908
> > >      >
> > >      > Many thanks,
> > >      > -T
> > > 
> > >     And why do I have a broken pipe here?
> > > 
> > >     $ ps ax | grep [f]irefox | perl6 -ne 'say
> > >     $_.lines.sort.reverse.words[0];'
> > >     7380
> > >     7581
> > >     7698
> > >     13023
> > >     13767
> > >     22369
> > > 
> > >     $ ps ax | grep [f]irefox | perl6 -ne 'say
> > >     $_.lines.sort.reverse.words[0];' | sort -r
> > > 
> > >     Failed to write bytes to filehandle: Broken pipe
> > >         in block <unit> at -e line 1
> > > 
> 
> 
> 
> On 3/14/19 10:53 PM, Simon Proctor wrote:
> > 6am here and I'm not at a computer but I think your problem is trying to
> > use both -n which runs your code on each line of STDIN and lines.
> > 
> > Try one or the other see what happens.
> > 
> > Once I'm ambulant and at a computer I'll poke at it myself.
> 
> 
> Thank you anyway.
> 
> 
> $ ps ax | grep [f]irefox | perl6 -n 'my @x = $_.words[0].lines.reverse;
> print @x[0] ~ "\n";'
> Could not open my @x = $_.words[0].lines.reverse; print @x[0] ~ "\n";.
> Failed to stat file: no such file or directory
> 
> $ ps ax | grep [f]irefox | perl6 -e 'my @x = $_.words[0].lines.reverse;
> print @x[0] ~ "\n";'
> No such method 'words' for invocant of type 'Any'
>   in block <unit> at -e line 1

So a couple of things here.

1. Learn to use pgrep instead of the myriad variations of ps | grep;
   pgrep has been standardized by POSIX for a long time and is almost
   certainly available in all the installations that you will ever need
   to touch[1].

2. Since you need to process all of the input lines as a whole, and not
   one by one, the "-n" option is not for you - it works on a single line
   at a time.  Yes, it is possible to do stuff using the END phaser, but
   in this case that would be overkill.  So you really want to run perl6
   without -n and then read all of the lines from its standard input
   stream.

3. The standard input stream in Perl 6 is called $*IN (think of it as
   mostly equivalent to what <<>> and <> would read from in Perl 5, and
   pretty much the same thing as Perl 5's STDIN).  So you want to run
   ".lines" on $*IN.

4. You only want to run ".words" on each of the items that ".lines"
   returned; then you want to convert each of the first words to
   an integer and then you want to sort them in reverse and get
   the first item.

So here are things step by step, first without using pgrep:

[roam@straylight ~]$ ps ax | grep -e '[z]sh' | perl6 -e 'dd $*IN.lines'
(" 3469 pts/19   Ss+    0:01 -zsh", " 3876 pts/17   Ss     0:00 -zsh", " 8782 
pts/10   Ss     1:20 -zsh", "10041 pts/15   Ss     0:00 -zsh", "10257 pts/24   
Ss+    0:00 -zsh", "10523 pts/11   Ss     0:00 -zsh", "10728 pts/21   Ss     
0:00 -zsh", "10959 pts/12   Ss     0:00 -zsh", "11196 pts/22   Ss     0:00 
-zsh", "11236 pts/18   Ss+    0:00 -zsh", "17512 pts/1    Ss     0:00 -zsh", 
"17905 pts/2    Ss     0:00 -zsh", "18089 pts/20   Ss+    0:00 -zsh", "18846 
pts/5    Ss     0:00 -zsh", "19232 pts/6    Ss     0:00 -zsh", "19808 pts/7    
Ss+    0:02 -zsh", "20368 pts/13   Ss+    0:00 -zsh", "21046 pts/8    Ss     
0:00 -zsh", "21232 pts/14   Ss     0:00 -zsh", "24099 pts/9    Ss     0:00 
-zsh", "29673 pts/16   Ss+    0:02 -zsh").Seq

OK, so we have the lines read from the standard input; let's see if we
can get the first word of each line:

[roam@straylight ~]$ ps ax | grep -e '[z]sh' | perl6 -e 'dd $*IN.lines.map: 
*.words[0]'
("3469", "3876", "8782", "10041", "10257", "10523", "10728", "10959", "11196", 
"11236", "17512", "17905", "18089", "18846", "19232", "19808", "20368", 
"21046", "21232", "24099", "29673").Seq

Right, but we want them as integers, right?

[roam@straylight ~]$ ps ax | grep -e '[z]sh' | perl6 -e 'dd $*IN.lines.map: 
*.words[0].Int'
(3469, 3876, 8782, 10041, 10257, 10523, 10728, 10959, 11196, 11236, 17512, 
17905, 18089, 18846, 19232, 19808, 20368, 21046, 21232, 24099, 29673).Seq

Let's sort them in reverse; note that we need to put the whole construct
so far in parentheses - we can't just stick a ".sort" at the end, since
it will operate only on a single integer, and that makes no sense.  We
need to take the whole sequence returned by ".map" and then sort it:

[roam@straylight ~]$ ps ax | grep -e '[z]sh' | perl6 -e 'dd ($*IN.lines.map: 
*.words[0].Int).sort.reverse'            
(29673, 24099, 21232, 21046, 20368, 19808, 19232, 18846, 18089, 17905, 17512, 
11236, 11196, 10959, 10728, 10523, 10257, 10041, 8782, 3876, 3469).Seq

And now to only get the largest process ID:

[roam@straylight ~]$ ps ax | grep -e '[z]sh' | perl6 -e 'dd ($*IN.lines.map: 
*.words[0].Int).sort.reverse[0]'
29673

Actually we can put the parentheses in a slightly different place, too:

[roam@straylight ~]$ ps ax | grep -e '[z]sh' | perl6 -e 'dd 
$*IN.lines.map(*.words[0].Int)'                
(3469, 3876, 8782, 10041, 10257, 10523, 10728, 10959, 11196, 11236, 17512, 
17905, 18089, 18846, 19232, 19808, 20368, 21046, 21232, 24099, 29673).Seq

OK, now let's see if pgrep would have helped:

[roam@straylight ~]$ pgrep zsh | perl6 -e 'dd 
$*IN.lines.map(*.Int).sort.reverse[0]'
29673

Yep, thought so :)  However... hm, you say you want the largest process
ID, but I'm not sure that this is *really* what you *need*; do you not
need the process that *started the most recently*?  (you know, on a long
running system the process IDs may wrap; this depends on the system,
some of them have really, really large process IDs, but some of them
also use them for other purposes, so still).  Unfortunately, this is
the point where the fun of using standardized utilities ends, since
for this next step it would be best to have a BSD-like ps(1) which
understands "-o" and has the "etime" format specifier.  So, left as
an exercise for the reader, how about this:

ps x -o pid,comm,etime | perl6 -e 'dd $*IN.lines.map({ /^ \s* $<pid> = [\d+] 
\s+ "zsh" \s .* \s+ $<elapsed> = [ <[- \d :]> + ] $/ ?? (~$/<pid> => (0, 0, 0, 
|$/<elapsed>.split(/<[-:]>/).map(*.Int))[*-4..*]) !! Any 
}).grep(*.defined).sort(*.value)[0].key'

Yes, I know it's a lot :) Take a look at it, see if you can break it
down into meaningful parts, see how those parts interplay; if you have
any questions, feel free to ask.  And, BTW, yes, on my Debian system
this showed a process with ID 29673 running for more than 20 days and
then a process with ID 23280 running for less than thirty minutes, so,
yes, this is what you need, not the largest process ID.

...okay, okay, here goes the very complex line above changed into
a somewhat readable program:

#!/usr/bin/env perl6

use v6.c;

sub pad-elapsed($elapsed) {
        my @ints = $elapsed.split(/<[-:]>/).map: *.Int;
        my @padded = (0, 0, 0, |@ints);
        return @padded[*-4..*];
}

sub is-ours($line) {
        $line ~~ /^ \s* $<pid> = [\d+] \s+ "zsh" \s .* \s+ $<elapsed> = [ <[- 
\d :]> + ] $/
                ?? (~$/<pid> => pad-elapsed $/<elapsed>)
                !! Any
}

my @only-ours = $*IN.lines.map(&is-ours);
my @only-real-ones = @only-ours.grep(*.defined);
my @sorted = @only-real-ones.sort(*.value);
my $latest-pid = @sorted[0].key;

say $latest-pid;

Hope that helped!

G'luck,
Peter

[1] The "almost certainly" is because, yes, yes, I know, I also have that
    dusty old HP/UX crunching away in a customer's basement; still.

-- 
Peter Pentchev  roam@{ringlet.net,debian.org,FreeBSD.org} p...@storpool.com
PGP key:        http://people.FreeBSD.org/~roam/roam.key.asc
Key fingerprint 2EE7 A7A5 17FC 124C F115  C354 651E EFB0 2527 DF13

Attachment: signature.asc
Description: PGP signature

Reply via email to