1.忽略标题,看看以下问题
file1.txt file2.txt file3.txt
是Windows下用Notepad++生成的三个小文件,现在将它们拷贝到Linux下面。
它们的内容分别是:
$ head file*
==> file1.txt <==
ABC
ABCD
ABCDE
==> file2.txt <==
George 120
Peppa 130
Susy 140
==> file3.txt <==
Susy
Peppa
Danny
Richard
George
- file1是几行字符串,待会儿需要输出它们的长度
- file2和3是含有名字的文件,待会儿需要根据file2的内容,判断file3中各个名字是否在file2中出现
2.问题1:求字符串长度
$ cat 1.pl
#! /usr/bin/perl
use warnings;
use strict;
open my $fh1, "<", "file1.txt";
while (<$fh1>) {
chomp $_;
print length($_)."\n";
}
close $fh1;
$ perl 1.pl
4
5
6
字符串长度都比实际值多1,用命令行试一下
$ awk '{print length($0)}' file1.txt
4
5
6
还是多1
这种情况下如果在主程序中运用了if+字符串长度判断,可能永远也不会得到想要的结果。
3.问题2:查找字符串
$ cat 2.pl
#! /usr/bin/perl
use warnings;
use strict;
open my $fh1, "<", "file2.txt";
my %name_exists = ();
while (<$fh1>) {
chomp $_;
my @oneline = (split(/\t/, $_));
$name_exists{$oneline[0]} = 1;
}
close $fh1;
open my $fh2, "<", "file3.txt";
while (<$fh2>) {
chomp $_;
if (exists $name_exists{$_}) {
print "$_\t出现过\n";
} else {
print "$_\t没有出现过\n";
}
}
close $fh2;
$ perl 2.pl
Susy 没有出现过
Peppa 没有出现过
Danny 没有出现过
Richard 没有出现过
George 没有出现过
问题出在哪里
4.Windows和Linux环境下,文件换行符不同
在windows下的文本文件的每一行结尾,都有一个回车('\n')和换行('\r')
在linux下的文本文件的每一行结尾,只有一个回车('\n');
可以在Notepad++中看到这种区别:菜单栏选择“视图”——“显示符号”——“显示所有字符”。
Windows文件行尾显示
Linux文件行尾显示
Linux终端下面也能看到区别
awk '{print $1"---"}' file1.txt | less
#显示
ABC^M---
ABCD^M---
ABCDE^M---
awk '{print $1"---"}' file3.txt | less
#显示
Susy^M---
Peppa^M---
Danny^M---
Richard^M---
George^M---
这就是为什么会出错的原因
每行多了一个^M
这导致字符串长度+1
也导致$hash{"Peppa"}变成了$hash{"Peppa^M"}, 问题2中的名字都识别不了
5.怎么避免这个问题?
在Linux下面生成一个文件(需要简单输入几个字符,比如1换行2换行3),拖到Windows下面,用Notepad++打开后清空内容,将原文件的内容(比如这里的file1.txt)复制拷贝到这上面,再重新命一个名即可(比如file1_new.txt)。这样这个新文件在Linux和Windows下面都能正常被Perl处理。
另外可以使用命令行, 效果相同
dos2unix file3.txt
sed -i 's/\r//g' file2.txt
我的疑问:是否可以在脚本中识别这种^M的情况,并在脚本中解决它,欢迎在下方评论指出,谢谢!
网友评论