http://qs321.pair.com?node_id=118363

Elvis has asked for the wisdom of the Perl Monks concerning the following question:

Hi,
Just for fun, I'd like to use perl instead of sed on the following line:

echo $HOME/Mail/* |sed 's/sent-mail //

So far, I've tried various things that leave me with no output or wrong output. E.g:

echo $HOME/Mail/* | perl -e 'while (<STDIN>=~s/sent-mail//) { print " +$_"}'

I've had a look at the Capturing input from pipe? node, but I'm still clueless. I've also used the s2p (sed2perl) program, but the output seems far from succint. I thought perl would be able to do the same task in as short a line as the sed command. Can it?

I'm very much a perl novice (initiate even), and would really appretiate your help.

Thank You.

Replies are listed 'Best First'.
Re: Another Q about piping Perl
by stefp (Vicar) on Oct 12, 2001 at 03:18 UTC
    The idiom to execute perl statements on and print the result of each line of a file is
    perl -pe 'perl_statements' < file
    or
    some_command | perl -pe 'perl_statements'

    each line is stored in $_ on which perl_statements act.

    Here you want to print all the files in the $HOME/Mail directory. An all perl solution is:
       map{ -f  $_  and print "$_ " } <$ENV{HOME}/MAIL/*>

    Some people consider using map on empty context is bad form. I don't. They would propose instead:   for(<$ENV{HOME}/MAIL/*>) {  -f  $_  and print "$_ " }
    or
      -f  $_  and print "$_ " for  <$ENV{HOME}/MAIL/*>

    TMTOWTDI

    -- stefp

      stefp wrote:

      Some people consider using map on empty context is bad form. I don't.

      I think it depends on the context. If you're doing a short one-liner like that, it's not a big deal. In fact, if you're just writing a small "throw away" script that only gets used once or twice and you don't care about performance or memory, then it's not a big deal IMHO. However, if you're writing large applications, it pays to be rigorous. Creating a bunch of only to throw away the return value is a waste of resources and a for loop is preferable. Doing what you did to print all the files in the $HOME/MAIL/ directory:

      # print all files in the directory (an overblown and limited 'ls' +or 'dir' perl -e '-f $_ and print "$_ " for glob(shift)' ./*

      Side note: since I tested that on a Windows box and it doesn't like single quotes on the command line and I hate using \" all the time to embed quotes, I wrote this:

      perl -e "-f $_ and print $_.$,.$/ for glob(shift)" ./*

      No wonder people say Perl has too much punctuation :)

      Cheers,
      Ovid

      Update: Hmm... seems I wasn't paying attention to blakem's post.

      Vote for paco!

      Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

      I like map as much as the next guy (see the "extended" Location field on my homenode) but why not write the above map as:
      -f $_ && print "$_ " for <$ENV{HOME}/MAIL/*>

      -Blake

Re: Another Q about piping Perl
by tommyw (Hermit) on Oct 12, 2001 at 03:20 UTC

    Well, the error message about being unable to modify <HANDLE> might be considered a bit of a clue: grab the input, and modify it separately:

    echo $HOME/Mail/* | perl -e 'while (<STDIN>) { s/sent-mail//; print "$ +_"}'

    Or just use the -p option, and really make it look like your sed command:

    echo $HOME/Mail/* | perl -p -e '/sent-mail//'

    update:Whoops. Of course, the missing s before the substitution string was meant as an exercise for the reader ;) echo $HOME/Mail/* | perl -p -e 's/sent-mail//'

    But personally, I'd stick with sed, if I've got the choice: it's less memory hungry for such simple tasks

Re: Another Q about piping Perl
by thatguy (Parson) on Oct 12, 2001 at 03:20 UTC
    I am not sure if you are trying to exclude the sent-mail folder or what.. if you are just pulling out the phrase 'sent-mail' (which will pull it out of even recieved mail) then this will work:
    echo $HOME/Mail/* | perl -e 'while(<>){$_=~ s/sent-mail//;if($_){print}}'

    if you just want the received mail, then you are better off with this:

    echo $HOME/Mail/received | perl -e 'print <>'
    -p

Re: Another Q about piping Perl
by chazzz (Pilgrim) on Oct 12, 2001 at 13:53 UTC
    Here's my take on this...

    perl -e "while(<>){s/sent-mail //;print;}"

    Short and sweet :)
(tye)Re: Another Q about piping Perl
by tye (Sage) on Oct 12, 2001 at 19:50 UTC

    Several replies mention "-pe" but the default behavior of 'sed' is actually best duplicated with "-ne": echo $HOME/Mail/* | perl -ne "print if s/sent-mail //"

            - tye (but my friends call me "Tye")
Re: Another Q about piping Perl
by Elvis (Sexton) on Oct 12, 2001 at 21:23 UTC

    Thanks for the excellent replies.

    FWIW, I'm trying to exculde my sent-mail folder from the listing. It's to do with my .muttrc file.

    I'm not too sure I understand the map function well, but it made interesting reading. Also in future, I'm going to have to take more notice of the perl --help output. :)

    Thanks Again.