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
signature.asc
Description: PGP signature