tags:

views:

300

answers:

5

By default, perl prints \r\n in a win32 environment. How can I override this? I'm using perl to make some changes to some source code in a repository, and I don't want to change all the newline characters.

I tried changing the output record separator but with no luck.

Thanks!

Edit: Wanted to include a code sample - I'm doing a search and replace over some files that follow a relatively straightforward pattern like this:

#!/usr/bin/perl
# test.pl

use strict;
use warnings;

$/ = undef;
$\ = "\n"; 
$^I=".old~";

while (<>) {
  while (s/hello/world/) {

  }
  print;
}

This should replace any instances of "hello" with "world" for any files passed on the cmd line.

Edit 2: I tried the binmode as suggested without any luck initially. I delved a bit more and found that $^I (the inplace edit special variable) was overriding binmode. Any work around to still be able to use the inplace edit?

Edit 3: As Sinan points out below, I needed to use binmode ARGVOUT with $^I instead of binmode STDOUT in my example. Thanks.

+2  A: 

Does binmode( STDOUT ) work?

PP
+1, yes, partially ... see edit. thx.
Keith Bentrup
Thanks Keith.....
PP
A: 

A unix newline is a LINEFEED character, which is ASCII code 10.

print "\012";

Chris Cleeland
On Windows: `perl -e "print qq{\012}" | xxd` yields `0000000: 0d0a` unless you set `binmode STDOUT`.
Sinan Ünür
It's not a problem with getting the right character. It's the text-mode translation that's modifying the output while writing to a text filehandle.
brian d foy
thanks for correcting me on Windows; I'd forgotten that perl "helped" even when explicitly told what to do.
Chris Cleeland
+8  A: 

Printing "\n" to a filehandle on Windows emits, by default, a CARRIAGE RETURN ("\015") followed by a LINE FEED ("\012") character because that the standard newline sequence on Windows.

This happens transparently, so you need to override it for the special filehandle ARGVOUT (see perldoc perlvar):

#!/usr/bin/perl -i.bak

use strict; use warnings;

local ($\, $/);

while (<>) {
    binmode ARGVOUT;
    print;
}

Output:

C:\Temp> xxd test.txt
0000000: 7465 7374 0d0a 0d0a                      test....

C:\Temp> h test.txt

C:\Temp> xxd test.txt
0000000: 7465 7374 0a0a                           test..

See also perldoc open, perldoc binmode and perldoc perliol (thanks daotoad).

Sinan Ünür
It's not really the \n doing anything. It's the filehandle translating \012. That is, without writing to a text filehandle, a \n is still just \012.
brian d foy
@brian d foy: Clarification added.
Sinan Ünür
For detailed discussion of Perl IO layers, the mechanism that does this translation, see perldoc perliol - http://perldoc.perl.org/perliol.html
daotoad
+1 Thx, it partially worked. Initially, I couldn't get binmode to do what you described. Then I traced it down to $^I. See my edit. Any work around.
Keith Bentrup
binmode ARGVOUT did the trick with the inplace edit. Thanks again!
Keith Bentrup
A: 

The data you are reading in contains line endings, so you're getting them back out again. You can strip them off yourself with chomp, then add your own ending back, provided you have set binmode as Sinan describes::

while (<>) {
    binmode;
    chomp;        # strip off \r\n
    while (s/search/replace/) {
        # ...
    }
    print;
    print "\n";   # add your own line ending back
}
Ether
+1  A: 

Re: your question about the binmode being lost when $^I opens a new output handle, you could solve this with the open pragma:

use open OUT => ':raw';

which will force all filehandles opened for writing to have the ':raw' PerlIO layer (equivalent to binmode with no argument) to apply to them. Just take care if you're opening anything else for output that you apply :crlf or any other layer as needed.

hobbs