背景
在Windows上使用Perl判断文件时何种换行符时,处理CR LF类型的换行符时,也识别成了LF。
思路
- Windows上的换行是 CRLF , Unix上是 LF , Mac CR
- 在Windows平台使用Perl读取文件创建文件句柄时,未对file handler设置binmode,了解到binmode模型作用是采用非二进制读取模式时,双字节换行符CR LF在读取时转换为LF,写入时将LF转换为CR LF。这对于使用双字节分隔文本文件行的操作系统(MS-DOS)至关重要,但对使用单个字符的操作系统(Unix,Mac OS,QNX)没有影响。
- chomp是去除每行行末的记录分隔符(record separator),这个分隔符的值是可以通过 perl内置变量 $/ (input record separators )来设置,默认情况下Windows和Linux上 $/ 的值都是 LF
处理
所以Perl脚本在读取DOS文本时,行末换行符CR LF 被自动转行成 LF ,此后去判断单行记录时,返回结果均是LF,未能正确识别出文件的换行符类型,基于此原因。修改代码如下(测试)
perl
#!/usr/bin/perl
use strict;
my $path = '/export/script/perl_scripts';
my @files = qw /a.txt b.txt/;
my $newLine = '';
for my $f (@files)
{
my $fullPath = sprintf "%s/%s",$path,$f;
# 获取首行
open(INFILE,$fullPath) or die "dont open this file ${fullPath}";
# 此函数设置在操作系统上以二进制形式读取和写入FILEHANDLE的格式。
# 采用非二进制读取模式时,双字节换行符CR LF在读取时转换为LF,写入时将LF转换为CR LF。
# 这对于使用双字节分隔文本文件行的操作系统(MS-DOS)至关重要,但对使用单个字符的操作系统(Unix,Mac OS,QNX)没有影响。
binmode(INFILE); # 设置二进制读取模式,保留文件中的原始换行符
my $line = <INFILE>;
close INFILE;
if($line =~ '\r\n')
{
$newLine = 'CRLF';
print "windows newline\n";
}elsif($line =~ '\n')
{
$newLine = 'LF';
print "linux newline\n";
}elsif($line =~ '\r')
{
$newLine = 'CR';
print "mac newline\n";
}else
{
print "is a single line without newline\n";
}
print "${fullPath} newline is ${newLine}\n";
# 采用如下去除换行符方式,替换chomp方法,可在任意平台处理任意换行符类型的文件
$line =~ s/[\r\n]+\Z//g;
}
## 运行结果如下
# linux newline
# /export/script/perl_scripts/a.txt newline is LF
# windows newline
# /export/script/perl_scripts/b.txt newline is CRLF
思路源自:https://blog.csdn.net/fibonaccian/article/details/42168725