11

我正在寻找一些适用于 Linux 的命令行工具,它们可以帮助我检测并将文件从iso-8859-1windows-1252等字符集转换为utf-8以及从 Windows 行尾转换为 Unix 行尾。

我需要这个的原因是我正在通过 SFTP 使用 Windows 上的编辑器(如 Sublime Text)在 Linux 服务器上处理项目,这些编辑器不断地搞砸这些事情。现在我猜我的文件大约有一半是utf-8,其余的是iso-8859-1windows-1252因为看起来 Sublime Text 只是在我保存文件时选择文件包含的字符集。即使我在选项中指定默认行结尾是LF,行结尾总是 Windows 行结尾,所以我的文件中大约有一半有LF,一半是CRLF

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

任何关于该主题的评论和个人经验也将受到欢迎。

谢谢


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

$ tree -f -i -a -I node_modules --noreport -n | xargs 文件 | grep -v 目录
./config.json:ASCII C++ 程序文本
./debugserver.sh:ASCII 文本
./.gitignore:ASCII 文本,没有行终止符
./lib/config.js:ASCII 文本
./lib/database.js:ASCII 文本
./lib/get_input.js:ASCII 文本
./lib/models/stream.js:ASCII 英文文本
./lib/serverconfig.js:ASCII 文本
./lib/server.js:ASCII 文本
./package.json:ASCII 文本
./public/index.html:HTML 文档文本
./src/config.coffee:ASCII 英文文本
./src/database.coffee:ASCII 英文文本
./src/get_input.coffee:ASCII 英文文本,带有 CRLF 行终止符
./src/jtv.coffee:ASCII 英文文本
./src/models/stream.coffee:ASCII 英文文本
./src/server.coffee:ASCII 文本
./src/serverconfig.coffee:ASCII 文本
./testserver.sh:ASCII 文本
./vendor/minify.json.js:ASCII C++ 程序文本,带有 CRLF 行终止符

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

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

另外为什么它显示charset=us-ascii而不是utf-8?什么是text/x-c++?有没有一种方法可以只输出charset=utf-8每个line-terminators=LF文件?

4

3 回答 3

12

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

Sublime Text 2 状态栏

如果编码错误,我可以File->Save with Encoding。如果行尾错误,后一个插件会附带更改行尾的命令:

Sublime Text 2 commands

于 2012-12-05T02:18:47.740 回答
3

如果一个文件没有 BOM,并且在file查看的文本量中没有“有趣的字符”,file则得出结论它是ASCIIISO-646——UTF-8 的严格子集。您可能会发现将 BOM 放在所有文件上会鼓励所有这些 Windows 工具正常运行;UTF-8 文件上的 BOM 约定起源于 Windows。或者它可能会使事情变得更糟。至于 x/c++,嗯,这只是file试图提供帮助,但失败了。你的javascript中有一些看起来像C++的东西。

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

于 2012-01-22T13:35:03.193 回答
2

而不是file,尝试使用自定义程序来检查您想要的东西。这是一个快速破解,主要基于一些谷歌点击,这些点击是由@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 位编码的概念 -unknown如果它既不是纯 7 位 ASCII 也不是正确的 UTF-8,它将简单地抛出。

于 2012-01-27T12:28:35.393 回答