open FILEHANDLE, '/etc/hosts' or die $!;
my $string = do { local $/; <FILEHANDLE> };
print($string);
The output of this Perl code is roughly:
127.0.0.1 localhost
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
That is, the entire contents of /etc/hosts.
Q&A
The difficult part to understand is line 2. In conventional Perl, reading a file’s complete contents would use a while loop to read line by line:
open FILEHANDLE, '/etc/hosts' or die $!;
my $string;
while (<FILEHANDLE>) {
$string .= $_;
}
Here’s a detailed explanation of line 2:
do { <block> }is a code block in Perl. The function’s return value is the last statement in<block>.<FILEHANDLE>is the last statement in the abovedo { <block> }, thus the return value. In Perl,<FILEHANDLE>’s return value has two different results depending on context:
my $scalar = <FILEHANDLE>; # When left side is scalar, returns single line of file
my @array = <FILEHANDLE>; # When left side is array, returns entire file (each line maps to array element)
- The
$/variable setting is key to this syntax sugar.$/is the input record separator, which defaults to newline. That is,<FILEHANDLE>’s default behavior of returning single-line content in scalar context is determined by the$/variable. Andlocal $/is equivalent tolocal $/ = undef - Difference between
localandmy:mycreates a new variable, whilelocaltemporarily changes a variable’s value (within scope)
Overall, this creates a temporary scope through do {}, changes the value of $/ within the scope, changes the separator for <FILEHANDLE> in scalar context (from \n to undef), achieving the goal of reading the entire file content.
References
- The difference between my and local https://www.perlmonks.org/?node_id=94007
- Perl Idioms Explained - my $string = do { local $/; }; https://www.perlmonks.org/?node_id=287647