Re: What's the safest @*ARGS form? (...was Re: Any other way to do this)
Replying to my own question here, The feedback I received at our latest Raku Meetup suggested that pulling in numeric data off the bash command line is okay--just as long as you know what you're doing. In the second example below, Raku will convert "1_000" to Rat 1000 (previously mentioned in last email). In the fourth, fifth, and sixth examples below, bash will perform 'brace expansion' before sending arguments onto Raku: ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' 200 300 apples 400oranges 2kilos 18.7876 518.7876 ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' 1_000 200 300 apples 400oranges 2kilos 18.7876 1518.7876 ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' {1000} 200 300 apples 400oranges 2kilos 18.7876 518.7876 ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' 1{10,20,30}0 200 300 apples 400oranges 2kilos 18.7876 4118.7876 ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' 1{10,20,30}0 3600 ~$ raku -e 'say @*ARGS.grep(*.Rat);' 1{10,20,30}0 (1100 1200 1300) Note, pulling the same data into Raku via a literal will simply delete the curly braces in the last two lines above. Nonetheless, it might be better to feed data to Raku via a file (or via a literal), rather than let bash muck with it: ~$ raku -e 'say "1{10,20,30}0".words.grep(*.Rat).sum;' 430 ~$ raku -e 'say "1{10,20,30}0".words.grep(*.Rat);' (110 20 300) HTH, Bill. https://www.linux.com/topic/desktop/all-about-curly-braces-bash/ On Tue, Sep 1, 2020 at 9:57 AM William Michels wrote: > On Tue, Sep 1, 2020 at 8:27 AM Brian Duggan wrote: > > > > On Monday, August 31, Bruce Gray wrote: > > > I finally settled on using `try` instead of numeric coercion, because > > > if I am not golfing, I think `try` makes the grep look more like > > > “filter out the non-numbers” instead of “get rid of the zero values”. > > > > Another option is to use 'val' -- which parses it as a literal -- > > > > $ raku -e 'say @*ARGS.map: { val($_) ~~ Numeric }' 1 2 3 a 1e10 > >(True True True False True) > > > > Brian > > > > I just wanted to point out to Radhakrishnan that Raku appears to do a good > job of weeding out erroneous "number-like" input, but using the approach > below Raku (as a feature) will accept "1_000" or "1_000_000" etc. as valid > numeric input: > > ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' 0 100 200 300 apples 400oranges > 2kilos 18.7876 > 618.7876 > ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' 0-0 100 200 300 apples > 400oranges 2kilos 18.7876 > 618.7876 > ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' 0/0 100 200 300 apples > 400oranges 2kilos 18.7876 > 618.7876 > ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' 10/0 100 200 300 apples > 400oranges 2kilos 18.7876 > Attempt to divide by zero when coercing Rational to Str > in block at -e line 1 > > ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' 5-0 100 200 300 apples > 400oranges 2kilos 18.7876 > 618.7876 > ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' 100 200 300 apples 400oranges > 2kilos 18.7876 > 618.7876 > ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' -100 200 300 apples 400oranges > 2kilos 18.7876 > 418.7876 > ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' --100 200 300 apples 400oranges > 2kilos 18.7876 > 518.7876 > ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' 1_000 200 300 apples 400oranges > 2kilos 18.7876 > 1518.7876 > ~$ > > > So, this all brings up the question of @*ARGS safety. Bruce said that the > shell (bash, ksh, whatever) is responsible for feeding arguments to Raku. > Are there any safety-traps lurking with one @*ARGS approach versus another? > I'm sifting through two articles right now, one by brian d foy entitled > "Quoting the Shell" and another by the author of a new shell called "Oil > shell", which (I presume) will be more secure than existing shells: > > "Quoting the Shell" > https://www.perl.com/article/quoting-the-shell/ > > "Why Create a New Unix Shell?" > https://www.oilshell.org/blog/2018/01/28.html > https://www.oilshell.org/ > > Also, a little more reference/best-practices here: > > "Filenames and Pathnames in Shell: How to do it Correctly" > https://dwheeler.com/essays/filenames-in-shell.html > > "Bash Pitfalls" > https://mywiki.wooledge.org/BashPitfalls > > "Writing Safe Shell Scripts" > https://sipb.mit.edu/doc/safe-shell/ > > "Shell Style Guide" > https://google.github.io/styleguide/shellguide.html > > "Tips on Good Shell Programming Practices" > > https://www.computerworld.com/article/2794462/tips-on-good-shell-programming-practices.html > > Best, Bill. >
What's the safest @*ARGS form? (...was Re: Any other way to do this)
On Tue, Sep 1, 2020 at 8:27 AM Brian Duggan wrote: > > On Monday, August 31, Bruce Gray wrote: > > I finally settled on using `try` instead of numeric coercion, because > > if I am not golfing, I think `try` makes the grep look more like > > “filter out the non-numbers” instead of “get rid of the zero values”. > > Another option is to use 'val' -- which parses it as a literal -- > > $ raku -e 'say @*ARGS.map: { val($_) ~~ Numeric }' 1 2 3 a 1e10 >(True True True False True) > > Brian > I just wanted to point out to Radhakrishnan that Raku appears to do a good job of weeding out erroneous "number-like" input, but using the approach below Raku (as a feature) will accept "1_000" or "1_000_000" etc. as valid numeric input: ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' 0 100 200 300 apples 400oranges 2kilos 18.7876 618.7876 ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' 0-0 100 200 300 apples 400oranges 2kilos 18.7876 618.7876 ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' 0/0 100 200 300 apples 400oranges 2kilos 18.7876 618.7876 ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' 10/0 100 200 300 apples 400oranges 2kilos 18.7876 Attempt to divide by zero when coercing Rational to Str in block at -e line 1 ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' 5-0 100 200 300 apples 400oranges 2kilos 18.7876 618.7876 ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' 100 200 300 apples 400oranges 2kilos 18.7876 618.7876 ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' -100 200 300 apples 400oranges 2kilos 18.7876 418.7876 ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' --100 200 300 apples 400oranges 2kilos 18.7876 518.7876 ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' 1_000 200 300 apples 400oranges 2kilos 18.7876 1518.7876 ~$ So, this all brings up the question of @*ARGS safety. Bruce said that the shell (bash, ksh, whatever) is responsible for feeding arguments to Raku. Are there any safety-traps lurking with one @*ARGS approach versus another? I'm sifting through two articles right now, one by brian d foy entitled "Quoting the Shell" and another by the author of a new shell called "Oil shell", which (I presume) will be more secure than existing shells: "Quoting the Shell" https://www.perl.com/article/quoting-the-shell/ "Why Create a New Unix Shell?" https://www.oilshell.org/blog/2018/01/28.html https://www.oilshell.org/ Also, a little more reference/best-practices here: "Filenames and Pathnames in Shell: How to do it Correctly" https://dwheeler.com/essays/filenames-in-shell.html "Bash Pitfalls" https://mywiki.wooledge.org/BashPitfalls "Writing Safe Shell Scripts" https://sipb.mit.edu/doc/safe-shell/ "Shell Style Guide" https://google.github.io/styleguide/shellguide.html "Tips on Good Shell Programming Practices" https://www.computerworld.com/article/2794462/tips-on-good-shell-programming-practices.html Best, Bill.
Re: Any other way to do this
On Monday, August 31, Bruce Gray wrote: > I finally settled on using `try` instead of numeric coercion, because > if I am not golfing, I think `try` makes the grep look more like > “filter out the non-numbers” instead of “get rid of the zero values”. Another option is to use 'val' -- which parses it as a literal -- $ raku -e 'say @*ARGS.map: { val($_) ~~ Numeric }' 1 2 3 a 1e10 (True True True False True) Brian
Re: Any other way to do this
I like your script, Bruce. And you are quite correct--my code seems to work just fine without ".words": ~$ raku -e 'say @*ARGS.grep(*.Rat).sum;' Best, Bill. On Mon, Aug 31, 2020 at 1:42 PM Bruce Gray wrote: > > Bill, > > You were correct that `!=== 0` is redundant in the original code, because a > numeric will be checked for zero-versus-not-zero in Boolean context, and > because `==` and `===` should mean the same thing when comparing a bare > numeric value. > > In your latest version, I want to point out that `.words` should be > redundant, since the shell will break up the command-line arguments on > whitespace, before ever handing them to Raku. > Your code gives the same answer without `.words`. > > Raku supports the procedural and functional (and OO, too!) paradigms very > well. > Here is a different version, for readers who have not yet embraced the > map/grep mindset we have been showing off. > > my @nums; > for @*ARGS -> $arg { > push @nums, $arg if $arg.Rat; > } > say @nums.sum; > > > -- > Hope this helps, > Bruce Gray (Util of PerlMonks) > > > > On Aug 31, 2020, at 3:02 PM, William Michels wrote: > > > > Very nice, Bruce and Daniel! > > > > I continued to hack on Rahakrishnan's code, then realized I could try > > using Bruce's grep() call as a filter: > > > > ~$ raku -e '@*ARGS.words.grep(*.Rat).sum.say;' 100 200 300 apples > > 400oranges 2kilos 18.7876 500 grams14 10stars10 sun100moon 77 > > 1195.7876 > > > > HTH, Bill. > > > > On Mon, Aug 31, 2020 at 12:23 PM wrote: > >> > >> I like Bruce's Regex-based approach. > >> > >> Here's how I'd probably approach the problem: > >> > >> raku -e 'say [+] @*ARGS.grep(+*)' 0 100 200 300 apples 400oranges 2kilos > >> 18.7876 500 grams14 10stars10 sun100moon 77 > >> > >> August 31, 2020 2:28 PM, "Bruce Gray" wrote: > >> > >>> my $is_a_number = / ^ \d+ [ '.' \d* ]? $ /; > >>> > >>> my $sum = @*ARGS.grep($is_a_number).sum; > >>> > >>> say $sum; > >>> > >>> — > >>> Hope this helps, > >>> Bruce Gray (Util of PerlMonks) > >>> > On Aug 31, 2020, at 12:22 PM, William Michels via perl6-users > wrote: > > I think it looks very good, Radhakrishnan! Presumably you are happy > with the sum 1195.7876? > > ~$ raku -e 'for @*ARGS {.say if ($_.Int // 0) };' 0 100 200 300 apples > 400oranges 2kilos 18.7876 500 grams14 10stars10 sun100moon 77 > 100 > 200 > 300 > 18.7876 > 500 > 77 > > I'm still mulling over whether or not the "!=== 0" is essential. I > have yet to mess-up the command line arguments sufficiently to require > it, and throwing a zero onto the command line seems to be handled > gracefully. > > Anyone else want to chime in? > > Best, Bill. > > On Mon, Aug 31, 2020 at 8:49 AM Radhakrishnan Venkataraman > wrote: > > Please see the following script that checks for type and sums up only > > the numbers passed as > > arguments to the script in the command line. I would be grateful if any > > improvement or furtherance > > to this script is offered. Thank you. > > > > # > > # sums the numbers given in command line arguments and prints > > # > > my $sum = 0; > > for @*ARGS > > { > > $sum += $_.Rat if $_.Int // 0 !=== 0; > > } > > say $sum; > > > > # > > # command line execution > > # perl6 cla.p6 100 200 300 apples 400oranges 2kilos 18.7876 500 grams14 > > 10stars10 sun100moon 77 > > # >
Re: Any other way to do this
Sorry Radhakrishnan, for mis-spelling your name in my last post. --B. On Mon, Aug 31, 2020 at 1:02 PM William Michels wrote: > > Very nice, Bruce and Daniel! > > I continued to hack on Rahakrishnan's code, then realized I could try > using Bruce's grep() call as a filter: > > ~$ raku -e '@*ARGS.words.grep(*.Rat).sum.say;' 100 200 300 apples > 400oranges 2kilos 18.7876 500 grams14 10stars10 sun100moon 77 > 1195.7876 > > HTH, Bill. > > On Mon, Aug 31, 2020 at 12:23 PM wrote: > > > > I like Bruce's Regex-based approach. > > > > Here's how I'd probably approach the problem: > > > > raku -e 'say [+] @*ARGS.grep(+*)' 0 100 200 300 apples 400oranges 2kilos > > 18.7876 500 grams14 10stars10 sun100moon 77 > > > > August 31, 2020 2:28 PM, "Bruce Gray" wrote: > > > > > my $is_a_number = / ^ \d+ [ '.' \d* ]? $ /; > > > > > > my $sum = @*ARGS.grep($is_a_number).sum; > > > > > > say $sum; > > > > > > — > > > Hope this helps, > > > Bruce Gray (Util of PerlMonks) > > > > > >> On Aug 31, 2020, at 12:22 PM, William Michels via perl6-users > > >> wrote: > > >> > > >> I think it looks very good, Radhakrishnan! Presumably you are happy > > >> with the sum 1195.7876? > > >> > > >> ~$ raku -e 'for @*ARGS {.say if ($_.Int // 0) };' 0 100 200 300 apples > > >> 400oranges 2kilos 18.7876 500 grams14 10stars10 sun100moon 77 > > >> 100 > > >> 200 > > >> 300 > > >> 18.7876 > > >> 500 > > >> 77 > > >> > > >> I'm still mulling over whether or not the "!=== 0" is essential. I > > >> have yet to mess-up the command line arguments sufficiently to require > > >> it, and throwing a zero onto the command line seems to be handled > > >> gracefully. > > >> > > >> Anyone else want to chime in? > > >> > > >> Best, Bill. > > >> > > >> On Mon, Aug 31, 2020 at 8:49 AM Radhakrishnan Venkataraman > > >> wrote: > > >>> Please see the following script that checks for type and sums up only > > >>> the numbers passed as > > >>> arguments to the script in the command line. I would be grateful if any > > >>> improvement or furtherance > > >>> to this script is offered. Thank you. > > >>> > > >>> # > > >>> # sums the numbers given in command line arguments and prints > > >>> # > > >>> my $sum = 0; > > >>> for @*ARGS > > >>> { > > >>> $sum += $_.Rat if $_.Int // 0 !=== 0; > > >>> } > > >>> say $sum; > > >>> > > >>> # > > >>> # command line execution > > >>> # perl6 cla.p6 100 200 300 apples 400oranges 2kilos 18.7876 500 grams14 > > >>> 10stars10 sun100moon 77 > > >>> #
Re: Any other way to do this
Very nice, Bruce and Daniel! I continued to hack on Rahakrishnan's code, then realized I could try using Bruce's grep() call as a filter: ~$ raku -e '@*ARGS.words.grep(*.Rat).sum.say;' 100 200 300 apples 400oranges 2kilos 18.7876 500 grams14 10stars10 sun100moon 77 1195.7876 HTH, Bill. On Mon, Aug 31, 2020 at 12:23 PM wrote: > > I like Bruce's Regex-based approach. > > Here's how I'd probably approach the problem: > > raku -e 'say [+] @*ARGS.grep(+*)' 0 100 200 300 apples 400oranges 2kilos > 18.7876 500 grams14 10stars10 sun100moon 77 > > August 31, 2020 2:28 PM, "Bruce Gray" wrote: > > > my $is_a_number = / ^ \d+ [ '.' \d* ]? $ /; > > > > my $sum = @*ARGS.grep($is_a_number).sum; > > > > say $sum; > > > > — > > Hope this helps, > > Bruce Gray (Util of PerlMonks) > > > >> On Aug 31, 2020, at 12:22 PM, William Michels via perl6-users > >> wrote: > >> > >> I think it looks very good, Radhakrishnan! Presumably you are happy > >> with the sum 1195.7876? > >> > >> ~$ raku -e 'for @*ARGS {.say if ($_.Int // 0) };' 0 100 200 300 apples > >> 400oranges 2kilos 18.7876 500 grams14 10stars10 sun100moon 77 > >> 100 > >> 200 > >> 300 > >> 18.7876 > >> 500 > >> 77 > >> > >> I'm still mulling over whether or not the "!=== 0" is essential. I > >> have yet to mess-up the command line arguments sufficiently to require > >> it, and throwing a zero onto the command line seems to be handled > >> gracefully. > >> > >> Anyone else want to chime in? > >> > >> Best, Bill. > >> > >> On Mon, Aug 31, 2020 at 8:49 AM Radhakrishnan Venkataraman > >> wrote: > >>> Please see the following script that checks for type and sums up only the > >>> numbers passed as > >>> arguments to the script in the command line. I would be grateful if any > >>> improvement or furtherance > >>> to this script is offered. Thank you. > >>> > >>> # > >>> # sums the numbers given in command line arguments and prints > >>> # > >>> my $sum = 0; > >>> for @*ARGS > >>> { > >>> $sum += $_.Rat if $_.Int // 0 !=== 0; > >>> } > >>> say $sum; > >>> > >>> # > >>> # command line execution > >>> # perl6 cla.p6 100 200 300 apples 400oranges 2kilos 18.7876 500 grams14 > >>> 10stars10 sun100moon 77 > >>> #
Re: Any other way to do this
I like Bruce's Regex-based approach. Here's how I'd probably approach the problem: raku -e 'say [+] @*ARGS.grep(+*)' 0 100 200 300 apples 400oranges 2kilos 18.7876 500 grams14 10stars10 sun100moon 77 August 31, 2020 2:28 PM, "Bruce Gray" wrote: > my $is_a_number = / ^ \d+ [ '.' \d* ]? $ /; > > my $sum = @*ARGS.grep($is_a_number).sum; > > say $sum; > > — > Hope this helps, > Bruce Gray (Util of PerlMonks) > >> On Aug 31, 2020, at 12:22 PM, William Michels via perl6-users >> wrote: >> >> I think it looks very good, Radhakrishnan! Presumably you are happy >> with the sum 1195.7876? >> >> ~$ raku -e 'for @*ARGS {.say if ($_.Int // 0) };' 0 100 200 300 apples >> 400oranges 2kilos 18.7876 500 grams14 10stars10 sun100moon 77 >> 100 >> 200 >> 300 >> 18.7876 >> 500 >> 77 >> >> I'm still mulling over whether or not the "!=== 0" is essential. I >> have yet to mess-up the command line arguments sufficiently to require >> it, and throwing a zero onto the command line seems to be handled >> gracefully. >> >> Anyone else want to chime in? >> >> Best, Bill. >> >> On Mon, Aug 31, 2020 at 8:49 AM Radhakrishnan Venkataraman >> wrote: >>> Please see the following script that checks for type and sums up only the >>> numbers passed as >>> arguments to the script in the command line. I would be grateful if any >>> improvement or furtherance >>> to this script is offered. Thank you. >>> >>> # >>> # sums the numbers given in command line arguments and prints >>> # >>> my $sum = 0; >>> for @*ARGS >>> { >>> $sum += $_.Rat if $_.Int // 0 !=== 0; >>> } >>> say $sum; >>> >>> # >>> # command line execution >>> # perl6 cla.p6 100 200 300 apples 400oranges 2kilos 18.7876 500 grams14 >>> 10stars10 sun100moon 77 >>> #
Re: Any other way to do this
my $is_a_number = / ^ \d+ [ '.' \d* ]? $ /; my $sum = @*ARGS.grep($is_a_number).sum; say $sum; — Hope this helps, Bruce Gray (Util of PerlMonks) > On Aug 31, 2020, at 12:22 PM, William Michels via perl6-users > wrote: > > I think it looks very good, Radhakrishnan! Presumably you are happy > with the sum 1195.7876? > > ~$ raku -e 'for @*ARGS {.say if ($_.Int // 0) };' 0 100 200 300 apples > 400oranges 2kilos 18.7876 500 grams14 10stars10 sun100moon 77 > 100 > 200 > 300 > 18.7876 > 500 > 77 > > I'm still mulling over whether or not the "!=== 0" is essential. I > have yet to mess-up the command line arguments sufficiently to require > it, and throwing a zero onto the command line seems to be handled > gracefully. > > Anyone else want to chime in? > > Best, Bill. > > On Mon, Aug 31, 2020 at 8:49 AM Radhakrishnan Venkataraman > wrote: >> >> Please see the following script that checks for type and sums up only the >> numbers passed as arguments to the script in the command line. I would be >> grateful if any improvement or furtherance to this script is offered. Thank >> you. >> >> # >> # sums the numbers given in command line arguments and prints >> # >> my $sum = 0; >> for @*ARGS >> { >> $sum += $_.Rat if $_.Int // 0 !=== 0; >> } >> say $sum; >> >> # >> # command line execution >> # perl6 cla.p6 100 200 300 apples 400oranges 2kilos 18.7876 500 grams14 >> 10stars10 sun100moon 77 >> #
Re: Any other way to do this
I think it looks very good, Radhakrishnan! Presumably you are happy with the sum 1195.7876? ~$ raku -e 'for @*ARGS {.say if ($_.Int // 0) };' 0 100 200 300 apples 400oranges 2kilos 18.7876 500 grams14 10stars10 sun100moon 77 100 200 300 18.7876 500 77 I'm still mulling over whether or not the "!=== 0" is essential. I have yet to mess-up the command line arguments sufficiently to require it, and throwing a zero onto the command line seems to be handled gracefully. Anyone else want to chime in? Best, Bill. On Mon, Aug 31, 2020 at 8:49 AM Radhakrishnan Venkataraman wrote: > > Please see the following script that checks for type and sums up only the > numbers passed as arguments to the script in the command line. I would be > grateful if any improvement or furtherance to this script is offered. Thank > you. > > # > # sums the numbers given in command line arguments and prints > # > my $sum = 0; > for @*ARGS > { > $sum += $_.Rat if $_.Int // 0 !=== 0; > } > say $sum; > > # > # command line execution > # perl6 cla.p6 100 200 300 apples 400oranges 2kilos 18.7876 500 grams14 > 10stars10 sun100moon 77 > #
Any other way to do this
Please see the following script that checks for type and sums up only the numbers passed as arguments to the script in the command line. I would be grateful if any improvement or furtherance to this script is offered. Thank you. # # sums the numbers given in command line arguments and prints # my $sum = 0; for @*ARGS { $sum += $_.Rat if $_.Int // 0 !=== 0; } say $sum; # # command line execution # perl6 cla.p6 100 200 300 apples 400oranges 2kilos 18.7876 500 grams14 10stars10 sun100moon 77 #