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

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

作者: TOP生物信息 | 来源:发表于2019-08-10 17:28 被阅读0次
    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

    相关文章

      网友评论

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

          本文链接:https://www.haomeiwen.com/subject/ymsrjctx.html