SPUG: itm 60 in effective perl programming

John W. Krahn krahnj at telus.net
Thu Feb 24 14:09:32 PST 2005

Ben Reser wrote:
> On Thu, Feb 24, 2005 at 02:33:26AM -0800, John W. Krahn wrote:
>>>$ echo 'foo' > test
>>>$ echo 'bar' >> test
>>>$ echo 'baz' >> test
>>>$ wc -l test
>>>     3 test
>>>$ perl -pe 's/\n/" " . <>/e' test
>>>foo bar
>>The two lines 'foo' and 'bar' *are* joined together!
> Umm but not baz.
>>>And in fact hangs until you Ctrl+D it if there is an odd number of lines
>>>in the file.
>>It didn't when I tried it and it shouldn't according to the documentation.
> It doesn't if you have an even number of lines.  An odd number and it
> does.  

I feel silly now.  I was streaming the the input to the perl program instead 
of reading from a file so it worked.  To get an odd number of lines from a 
file with an even number of lines I was using:

head -n -1 file | perl -pe 's/\n/" " . <>/e'

[big snip]

>>>Perhaps they meant this:
>>>perl -pe 's/\n/ /' file
>>>tr would probably be moderately better:
>>>perl -pe 'tr/\n/ /'
>>>But I'd prefer the following:
>>>perl -pe 'chomp; $_ .= " "' file
>>Your examples replace *every* newline with a space which is not what the
>>original does.
> Umm yes I realize that.  I even explained that.  The original doesn't
> join every line.  Which isn't what he said it did.  It joins every other
> line.  Which I suppose if that's what you want is fine but that's not
> what he said it did.
>>>I can't imagine why anyone would want to use the regex version.
>>Because the substitution operator allows you to _e_valuate the replacement
>>string as a perl expression.
> I'm fully aware of what the original is doing.  But if it's described as
> joining all the lines in a file it doesn't do that.  Just because you
> can use the regex operator to do something doesn't mean it's the most
> efficient.  And many times it's not the most readable.  
> IMHO this script is seriously bugged.  It's misusing the <> operator and
> I'm a bit suprised to hear that it was found in a book titled Effective
> Perl.

I guess you don't have the book?  From the chapter "Some interesting Perl 
one-liners." in "Effective Perl Programming" page 249:

perl -pe 's/\n/" " . <>/e' data

Randal posted something like this in response to a request for a program
that would take lines from a file and join them together in pairs.  For
example, here's an input file:


This one-liner turns the input into the following:

Testing one                                Each line is two of the old lines
two three                                  joined together with a space.

The -pe command line option used above (a combination of -p and -e)
yields a program that acts like the following:

while (<>) {
   s/\n/" " . <>/e;

I sputtered a bit when I saw this one-liner for the first time because I had
never thought of using <> in a substitution.  But it is fairly straightforward
otherwise.  Note that you have to substitute for \n.  Nothing else--for exam-
ple, the $ anchor--will work.

use Perl;

More information about the spug-list mailing list