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

In "man perlfunc," the unpack command has the heading:

unpack TEMPLATE,EXPR

The following code snippet works:

read FILNAM, $_, 16; $val = unpack 'H32';

But this does not:

$val = unpack 'H32', (read (FILNAM, $_, 16));

With the latter code, $val gets assigned 3136 (the hex string for 16). While I rank as a lowly novice, I still expected the one liner to work. Can someone explain (purely for my edification) why it doesn't?

Replies are listed 'Best First'.
Re: Reading and unpacking on one line
by choroba (Cardinal) on Nov 05, 2020 at 16:19 UTC
    From read:

    > Returns the number of characters actually read, 0 at end of file, or undef if there was an error

    Therefore, the second version is equivalent to

    $val = unpack 'H32', 16;

    because the read returned 16.

    If you only specify the template, unpack uses the default variable $_ as the value to unpack.

    You can use do to read and return the value you have just read:

    $val = unpack 'H32', do { read FILNAM, $_, 16; $_ };

    But you should check what read returned to handle possible errors.

    Also, calling a file handle FILNAM, which rather seems to be an abbreviation of "file name", is misleading.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]
Re: Reading and unpacking on one line
by tybalt89 (Monsignor) on Nov 05, 2020 at 16:31 UTC
    #!/usr/bin/perl use strict; # https://perlmonks.org/?node_id=11123425 use warnings; open FILNAM, '<', \<<END or die $!; 1234567890 abcdefghijkl END my $val = unpack 'H32', do { local $/ = \16; <FILNAM> }; print "$val\n";

    UPDATED: changed input to an in memory file to make program completely self contained.

      Thanks to all for the answers. I understand what happened now. :)

      I will ask you this, since you slightly changed the method used to read the data (not that I need to know for this particular case, but just want to increase my understanding in general) - how do I specify reading 16 characters (perhaps UTF-8, for example) versus reading 16 bytes (as in pure binary data?

      Thank you again

        The behaviour depends on the filehandle. It's documented at the end of read

        > depending on the status of the filehandle, either (8-bit) bytes or characters are read.

        Similarly, sysread:

        > Note that if the filehandle has been marked as ":utf8", Unicode characters are read instead of bytes

        So, to read UTF-8, open the file handle with the :encoding(UTF-8) layer.

        map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

        I don't do UTF. Maybe someone else will answer this.

Re: Reading and unpacking on one line
by BillKSmith (Monsignor) on Nov 05, 2020 at 16:15 UTC
    In the first case. you read 16 characters into $_ and then unpack the contents of $_. In the second case, you do the same read, but you unpack the return value of read (the number of characters actually read, 16).
    Bill