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

my $file = '/etc/redhat-release'; # content of /etc/redhat-release # CentOS Linux release 7.6.1810 (Core) open(SOURCE, '<', $file); <SOURCE> =~ m/(?<=release )\d/; close SOURCE; my $version = $&; print "The version is: $version\n";
How can I assign the string to the $version variable without using the '$&' ?

Replies are listed 'Best First'.
Re: Read text in file and assign to variable
by haj (Vicar) on Jan 22, 2024 at 13:12 UTC

    Just capture the match! You can get rid if the zero-width assertion at the same time:

    my $file = '/etc/redhat-release'; # content of /etc/redhat-release # CentOS Linux release 7.6.1810 (Core) open(SOURCE, '<', $file); my ($version) = <SOURCE> =~ m/release (\d)/; close SOURCE; print "The version is: $version\n";
      Thanks for the suggestions. Now I'm trying to understand why the $version variable must have brackets around it.

        Hello maxamillionk,

        Perl is context-sensitive, meaning the return value of a function (or, in this case, of a regular expression match) can change depending on what it's assigned to.

        If a match occurs in scalar context, the value returned is the number of matches. In the absence of the /g global modifier, this can only be 1 or 0, success or failure (where failure is indicated by the empty string: ''). my $version = ... puts what follows into scalar context, so the result will be either '1' or '', which is not what you want.

        In list context, the contents (i.e. the value) of the match is returned. Putting parentheses around the variable -- my ($version) = ... -- puts what follows into list context, so the result will be the version number matched (if any), which is what you are looking for here.

        Hope that helps,

        Athanasius <°(((><contra mundum סתם עוד האקר של פרל,

        In addition to ++Athanasius' excellent reply, note the examples in my earlier response.

        In the first, I put the match output into a list and assigned the 0th element:

        $version = (<$fh> =~ /(\d)/)[0];

        In the second, I used my ($version) = ..., as already explained.

        — Ken

Re: Read text in file and assign to variable
by kcott (Archbishop) on Jan 22, 2024 at 14:04 UTC

    G'day maxamillionk,

    Prefer a lexical filehandle in as small a scope as possible. This has these benefits:

    • There's no interference from another package variable called SOURCE.
    • The filehandle only exists for a limited time; i.e. it doesn't persist outside the limited scope.
    • Perl will automatically close the filehandle when the limited scope is exited.

    There's a variety of ways to achieve this. Here's two:

    $ perl -e ' my $file = "pm_11157157_text"; system cat => $file; my $version; { open my $fh, "<", $file; $version = (<$fh> =~ /(\d)/)[0]; } print "Version: $version\n"; ' # CentOS Linux release 7.6.1810 (Core) Version: 7
    $ perl -e ' my $file = "pm_11157157_text"; system cat => $file; my ($version) = do { open my $fh, "<", $file; <$fh> =~ /(\d)/; }; print "Version: $version\n"; ' # CentOS Linux release 7.6.1810 (Core) Version: 7

    You don't need release in the regex but you may want more than just "7" captured. Again, two possibilities:

    $ perl -e ' my $file = "pm_11157157_text"; system cat => $file; my ($version) = do { open my $fh, "<", $file; <$fh> =~ /([0-9.]+)/; }; print "Version: $version\n"; ' # CentOS Linux release 7.6.1810 (Core) Version: 7.6.1810
    $ perl -e ' my $file = "pm_11157157_text"; system cat => $file; my ($version) = do { open my $fh, "<", $file; <$fh> =~ /([0-9.]+.+$)/; }; print "Version: $version\n"; ' # CentOS Linux release 7.6.1810 (Core) Version: 7.6.1810 (Core)

    — Ken