如何确保我的所有源文件都使用Unix行结尾保留UTF-8?

时间:2012-01-22 13:02:34

标签: unix command-line character-encoding sublimetext line-endings

我正在寻找一些Linux的命令行工具,可以帮助我检测和转换字符集中的文件,如 iso-8859-1 windows-1252 utf-8 ,从Windows行结尾到Unix行结尾。

我需要这个的原因是我正在通过SFTP在Linux服务器上开展项目,在Windows上使用编辑器(如Sublime Text),这些项目只是不断地搞砸了。现在我猜我的一半文件是 utf-8 ,其余的是 iso-8859-1 windows-1252 因为它似乎Sublime Text只是选择字符集,当我保存文件时,文件包含哪些符号。行结尾总是Windows行结尾,即使我在选项中指定默认行结尾是 LF ,因此大约一半的文件有 LF ,一半是< EM> CRLF

所以我至少需要一个工具来递归扫描我的项目文件夹,并提醒我那些偏离 utf-8 并带有 LF 行结尾的文件,这样我就可以在我将更改提交给GIT之前手动修复它。

欢迎任何有关该主题的评论和个人经历。

由于


编辑 我有一个临时解决方案,我使用treefile输出有关项目中每个文件的信息,但它有点不稳定。如果我没有为-i添加file选项,那么我的很多文件会得到不同的输出,例如 ASCII C ++程序文本 HTML文档文本英文文本等:

$ tree -f -i -a -I node_modules --noreport -n | xargs file | grep -v directory
./config.json:              ASCII C++ program text
./debugserver.sh:           ASCII text
./.gitignore:               ASCII text, with no line terminators
./lib/config.js:            ASCII text
./lib/database.js:          ASCII text
./lib/get_input.js:         ASCII text
./lib/models/stream.js:     ASCII English text
./lib/serverconfig.js:      ASCII text
./lib/server.js:            ASCII text
./package.json:             ASCII text
./public/index.html:        HTML document text
./src/config.coffee:        ASCII English text
./src/database.coffee:      ASCII English text
./src/get_input.coffee:     ASCII English text, with CRLF line terminators
./src/jtv.coffee:           ASCII English text
./src/models/stream.coffee: ASCII English text
./src/server.coffee:        ASCII text
./src/serverconfig.coffee:  ASCII text
./testserver.sh:            ASCII text
./vendor/minify.json.js:    ASCII C++ program text, with CRLF line terminators

但如果我确实包含-i,则不会显示行终止符:

$ tree -f -i -a -I node_modules --noreport -n | xargs file -i | grep -v directory
./config.json:              text/x-c++; charset=us-ascii
./debugserver.sh:           text/plain; charset=us-ascii
./.gitignore:               text/plain; charset=us-ascii
./lib/config.js:            text/plain; charset=us-ascii
./lib/database.js:          text/plain; charset=us-ascii
./lib/get_input.js:         text/plain; charset=us-ascii
./lib/models/stream.js:     text/plain; charset=us-ascii
./lib/serverconfig.js:      text/plain; charset=us-ascii
./lib/server.js:            text/plain; charset=us-ascii
./package.json:             text/plain; charset=us-ascii
./public/index.html:        text/html; charset=us-ascii
./src/config.coffee:        text/plain; charset=us-ascii
./src/database.coffee:      text/plain; charset=us-ascii
./src/get_input.coffee:     text/plain; charset=us-ascii
./src/jtv.coffee:           text/plain; charset=us-ascii
./src/models/stream.coffee: text/plain; charset=us-ascii
./src/server.coffee:        text/plain; charset=us-ascii
./src/serverconfig.coffee:  text/plain; charset=us-ascii
./testserver.sh:            text/plain; charset=us-ascii
./vendor/minify.json.js:    text/x-c++; charset=us-ascii

为什么它会显示 charset = us-ascii 而不是 utf-8 ?什么是 text / x-c ++ ?有没有办法只能为每个文件输出charset=utf-8line-terminators=LF

3 个答案:

答案 0 :(得分:12)

我最终得到的解决方案是两个Sublime Text 2插件“EncodingHelper”“LineEndings”。我现在在状态栏中获得文件编码和行结尾:

Sublime Text 2 status bar

如果编码错误,我可以文件 - &gt;使用编码保存。如果行结尾是错误的,后一个插件会带有更改行结尾的命令:

Sublime Text 2 commands

答案 1 :(得分:3)

如果文件没有BOM,并且file查看的文本数量中没有“有趣字符”,file会认为它是 ASCII ISO-646 - UTF-8的严格子集。您可能会发现将BOM放在所有文件上会鼓励所有这些Windows工具运行;源自Windows的UTF-8文件上的BOM的约定。或者它可能会使事情变得更糟。至于x / c ++,嗯,只是file试着帮助和失败。你的javascript里面有一些看起来像C ++的东西。

Apache Tika有一个编码检测器;您甚至可以使用它附带的命令行驱动程序作为file的替代方法。它将坚持使用MIME类型,而不是偏离C ++。

答案 2 :(得分:2)

尝试自定义程序来检查您想要的内容,而不是file。这是一个快速入侵,主要基于some Google hits,偶然由@ikegami撰写。

#!/usr/bin/perl

use strict;
use warnings;

use Encode qw( decode );

use vars (qw(@ARGV));

@ARGV > 0 or die "Usage: $0 files ...\n";

for my $filename (@ARGV)
{
    my $terminator = 'CRLF';
    my $charset = 'UTF-8';
    local $/;
    undef $/;
    my $file;
    if (open (F, "<", $filename))
    {
        $file = <F>;
        close F;    
        # Don't print bogus data e.g. for directories
        unless (defined $file)
        {
            warn "$0: Skipping $filename: $!\n;
            next;
        }
    }
    else
    {
        warn "$0: Could not open $filename: $!\n";
        next;
    }

    my $have_crlf = ($file =~ /\r\n/);
    my $have_cr = ($file =~ /\r(?!\n)/);
    my $have_lf = ($file =~ /(?!\r\n).\n/);
    my $sum = $have_crlf + $have_cr + $have_lf;
    if ($sum == 0)
    {
        $terminator = "no";
    }
    elsif ($sum > 2)
    {
        $terminator = "mixed";
    }
    elsif ($have_cr)    
    {
        $terminator = "CR";
    }
    elsif ($have_lf)
    {
        $terminator = "LF";
    }

    $charset = 'ASCII' unless ($file =~ /[^\000-\177]/);

    $charset = 'unknown'
        unless eval { decode('UTF-8', $file, Encode::FB_CROAK); 1 };

    print "$filename: charset $charset, $terminator line endings\n";
}

请注意,这没有传统8位编码的概念 - 如果它既不是纯粹的7位ASCII也不是正确的UTF-8,它只会抛出unknown