Use three-arg open.
Use lexical filehandles.
Check the open succeeded.
Yes, it is *always* needed as of 5.8. You can also combine this step
with the open:
open my $FH, '<:raw', $myfile
or die "can't read '$myfile': $!";
Don't use magic numbers for seek. Use the proper constants: it's
clearer, and safer if you ever port the code to a machine where SEEK_END
isn't 2 (such things do happen: GNU Hurd, for instance, has O_RDONLY
defined as 1 rather than 0).
use Fcntl qw/:seek/;
seek $FH, -2, SEEK_END;
Why do this? It just introduces an entirely unnecessary race condition,
and you haven't reopened it in binary mode, which may or may not be
important. If you wish to reinstate CRLF processing, you can say
binmode $FH, ':crlf';
It's not clear the OP wants to copy the file. If he wants to append, it
would be better to open in '+<' mode seek to the end before writing.
While I'm usually a fan of using regexes rather than more low-level
solutions, this is more complicated than necessary. Something like
seek $FH, -1, SEEK_END;
or die "can't seek '$myfile': $!";
read $FH, my $eol, 1
or die "can't read from '$myfile': $!";
seek $FH, 0, SEEK_END;
print $FH "\n" unless $eol =~ tr/\r\n//;
would be simpler. If you want to insert a newline matching the rest of
the file, you would need to read at least two characters, of course. For
normalizing newlines see PerlIO::eol.
Note also that "\r" and "\n" are not portable. Some systems have "\r" eq
"\012" and "\n" eq "\015". If you mean an ASCII CR say "\015".
Thanks Petr. The code works fine in detecting \r\n|\n|\r, but it fails
when the $lastchars are just normal characters. What I did was to
append a line of text to the file and I didn't want to have a blank
line if there is already \r\n|\n|\r. I ran your code once, it was OK
but the subsequent runs failed (I expected \n to be printed, but it
didn't).
It works for me here. Please post a complete script that shows how it
fails.
Note that text files *should* end with a trailing newline (in the
appropriate local format). If you have files that don't, they're
arguably broken, and you're better off fixing them than propagating the
error.
Ben