Windows和Linux环境下,文件换行符不同导致错误:行尾出

2019-08-10  本文已影响0人  TOP生物信息
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
  1. file1是几行字符串,待会儿需要输出它们的长度
  2. 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的情况,并在脚本中解决它,欢迎在下方评论指出,谢谢!


reference

https://hlee.iteye.com/blog/1476195

上一篇下一篇

猜你喜欢

热点阅读