strawberry-perlperl

How to print filtered output list of an external command in Perl?


I'm learning Perl. As an exersize, I try to print all installed Mojolicious modules. I'm using Strawberry Perl and don't have grep installed.

My naive try is:

perl -wE "for (sort `cpan -l`) { chomp; say if index($_, 'Mojo') == 0; };"

I found out that cpan -l returns a list. I expected a string, but never mind. I sort the returned list, chomp each record and say the ones that start with 'Mojo'.

It rather works, but prints each line twice:

Mojolicious::Sessions   undef
Mojolicious::Sessions   undef
Mojolicious::Static     undef
Mojolicious::Static     undef
Mojolicious::Types      undef
Mojolicious::Types      undef
Mojolicious::Validator  undef
Mojolicious::Validator  undef
Mojolicious::Validator::Validation      undef
Mojolicious::Validator::Validation      undef

What it is wrong that prints each record twice?

Edit:

I run the code under Cent OS. It looks like it works fine but have two versions of the libs installed.

perl -we 'for (sort `cpan -l`) { chomp; print $_, "\n" if index($_, "JSON") == 0; };'

JSON::PP        4.02
JSON::PP        4.04
JSON::PP::Boolean       4.02
JSON::PP::Boolean       4.04

Edit 2:

As recommended by @zdim, I checked the file paths of the installed modules. It appeared that there are doubled installations:

whichpm -a Mojolicious
C:\Strawberry\perl\site\lib\Mojolicious.pm
C:\Strawberry\perl\vendor\lib\Mojolicious.pm


whichpm -v Mojolicious
whichpm: WARNING: DUPLICATE module files found for 'Mojolicious':
  C:\Strawberry\perl\vendor\lib\Mojolicious.pm
Mojolicious     8.22    (non-core)      C:\Strawberry\perl\site\lib\Mojolicious.pm

It looks like the question was wrong.

A possible reason for the duplicated installation can be inproper modules update. After installing Strawbery I used the following command:

cpan-outdated -p | cpanm

Thank you guys for the help. It looks like it was the wrong question. I accept the given answer and will open a new 'better' question.


Solution

  • Not sure what cpan does and its man page is sprawling for me. Could it be listing modules from two Perl versions? Or there are indeed two versions of modules installed?

    Here is another option, with core ExtUtils::Installed

    perl -MExtUtils::Installed -MList::Util=max -wE'
        $obj = ExtUtils::Installed->new; 
        @mods = sort $obj->modules; 
        $max_len = max map { length } @mods; 
        printf("%-${max_len}s -- %s\n", $_, $obj->version($_)) for @mods'
    

    This prints all of them. To see just the ones starting with Mojo change the last line to

    /^Mojo/ and printf("%-${max_len}s -- %s\n", $_, $obj->version($_)) for @mods'
    

    The /^Mojo/ is a regex that tests $_ (by default) for whether it starts with (^ anchor) the literal string Mojo. This is I think clearer than using index, and is idiomatic (more readily understood).

    But printf has for the field width the length of the longest module name, found before filtering, which is likely too wide for the filtered list. So for nicer output you can first filter with grep

    my @mods_filtered = sort grep { /^Mojo/ } $obj->modules; 
    my $max_len = max map { length } @mods_filtered; 
    printf("%-${max_len}s -- %s\n", $_, $obj->version($_)) for @mods_filtered;
    

    All this should be in a small utility script; the one-liner above is for copy-paste testing.

    See documentation for details on what this module does.

    Also see this post, with code for another option -- to search for files directly.