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

In "Effective Perl Programming" (i read this from back to front now because I have read it so many times and keep hitting the same thing) Randal Schwartz offered the above as a way to take a file and join lines together in pairs. perl -pe 's/\n/" " . <>/e' data I have 2 questions about this: 1: what does /e do in a regexp? 2: if data is a filehande and this is a one-liner, how does data get input from a file with "\n"=separated values?

Replies are listed 'Best First'.
Re: codeperl -pe 's/\n/
by ZZamboni (Curate) on May 26, 2000 at 18:13 UTC
    I'm sure the author will be able to explain it better, but here it goes:
    • The -p option creates an implicit
      while(<>) { ... ; print }
      loop around your code (which takes the place of the "...").
    • The /e modifier causes the replacement part to be evaluated as a perl expression, so the
      " " . <>
      is evaluated as "a space concatenated with the next line read from the input".
    This makes more sense with an example. Let's say you have the file:
    one two three four
    And run it through the code above. Here's what happens:
    1. The "while(<>)" reads "one\n"
    2. The s substitutes the "\n" in "one\n" with a space followed by the next line in the file ("two\n"), so $_ now contains "one two\n".
    3. The implicit "print" (from the -p option) prints $_.
    4. Repeat.

    --ZZamboni

      while I have no doubt that this is basicaly correct, I'm not convinced that it's 100%

      My understanding of the situation is that the regular expression operator iterates over the entire string before it moves on to the "implicit" print. This makes the order

      1. The "while(<>)" reads "one\n"
      2. The s substitutes the "\n" in "one\n" with a space followed by the next line in the file ("two\n"), so $_ now contains "one two\n".
      3. Substitution operator now carries on examining $_, finds \n at the end "one two\n" etc.
      4. The implicit "print" (from the -p option) prints $_.

      If it did the print as step three, surely you would end up with

      one two
      three four

      Update nuance hangs his head in shame :-( I really will have to learn to read posts properly, of course the original node mentions joining pairs of lines. Doh!

      As you can all see, my understanding was wrong.

      Nuance

      Baldrick, you wouldn't see a subtle plan if it painted itself purple and danced naked on top of a harpsichord, singing "Subtle plans are here again!"

        The purpose of the snippet is precisely to join the lines of the file two at a time. So yes, the output you give is the one you get, but that is the intended effect. The -p adds an implicit print at each iteration of the implicit loop.
    A reply falls below the community's threshold of quality. You may see it by logging in.
Re: codeperl -pe 's/\n/
by jjhorner (Hermit) on May 26, 2000 at 18:11 UTC

    Well the /e means to evaluate the right side as an expression.

    When you have multiple lines in a text file, each line contains \n at the end. This is the most common line deliminator. A line is not defined as whatever is wrapped on your screen, but generally the space between your \n (newlines).

    When you grab a chunk of data using the angle brackets, by default it defines a chunk as the space between and including the trailing \n character.

    I hope this helps.

    J. J. Horner

    Linux, Perl, Apache, Stronghold, Unix

    jhorner@knoxlug.org http://www.knoxlug.org

Re: codeperl -pe 's/\n/
by KM (Priest) on May 26, 2000 at 18:24 UTC
    First, Randal may not have written that line, the primary author on that book is Joeseph Hall.

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

    This is a command line, obviously, and if you read perlrun, you will read that -p will make the assumption that there is a while() loop around your code. So, this would look similar to the following, to Perl:

    while (&lt;&gt;) { s/\n/" " . <>/e; }

    As stated in other responses the /e allows you to be able to evaluate things on the right side of an s///.
    2: if data is a filehande and this is a one-liner, how does data get input from a file with "\n"=separated values? It isn't a filehandle, it is a file name. It get's the the data with \n seperated values because that is what the lines of the file are seperated with. This is not different that opening a file and itterating over it from within a script.

    Cheers,
    KM

      I actually don't recall now whether I wrote it or Joseph did.:)
        Joseph said you suggested the shiny ball, and that's all you did ;) Just kidding. He never mentioned to me who did what, just gave me some pointers on authoring that came up from when he was working on it.

        Cheers,
        KM

Re: codeperl -pe 's/\n/
by swiftone (Curate) on May 26, 2000 at 18:28 UTC
    The answer to #1 is found in the perlop man page (NOT perlre, suprisingly enough). /e evaluates the right side of a s/// operation. In this example, " " . <> is evaluated rather than treated as a string.

    The answer to #2 lies in the <> operator. This is a magic operator that reads the next line of the file mentioned on the command line. The -p has perl loop over the -e'd string until complete, printing (see perlrun man page). So data isn't a filehandle, it's a filename.