Как убедиться, что все мои исходные файлы остаются UTF-8 с окончанием строки Unix?

Я ищу некоторые инструменты командной строки для Linux, которые могут помочь мне обнаружить и преобразовать файлы с наборов символов, таких как iso-8859-1 и windows-1252, в utf-8 и из концов строк Windows до окончаний строк Unix.

Причина, по которой я нуждаюсь в этом, - это то, что я работаю над проектами на серверах Linux через SFTP с редакторами в Windows (например, Sublime Text), которые просто постоянно закручивают эти вещи. Прямо сейчас я предполагаю, что половина моих файлов - utf-8, остальные - iso-8859-1 и windows-1252, поскольку кажется, что Sublime Text просто выбирает набор символов, с помощью которого хранятся файлы, которые он хранит, когда я его сохраняю. Окончаниями строк являются ВСЕГДА окончания строки Windows, даже если я указал в параметрах, что окончание строк по умолчанию - LF, поэтому около половины моих файлов имеют LF, а половина - CRLF.

Поэтому мне понадобится хотя бы инструмент, который бы рекурсивно просматривал мою папку проекта и предупреждал меня о файлах, которые отклоняются от utf-8 с концами строки LF, поэтому я мог бы вручную исправить это, прежде чем я вступлю в мои изменения в GIT.

Любые комментарии и личный опыт по этой теме также будут приветствоваться.

Спасибо


Изменить: У меня есть временное решение, в котором я использую tree и file для вывода информации обо всех файлах в моем проекте, но это довольно странно. Если я не включил параметр -i для file, тогда многие мои файлы получат разные результаты, такие как текст программы ASCII С++ и текст 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? А какой текст/x-С++? Есть ли способ, чтобы я мог выводить только charset=utf-8 и line-terminators=LF для каждого файла?

Ответ 1

В результате я получил два плагина Sublime Text 2 "EncodingHelper" и "LineEndings". Теперь я получаю как кодировку файла, так и конец строки в строке состояния:

Sublime Text 2 status bar

Если кодировка неверна, я могу Файл- > Сохранить с кодировкой. Если строки заканчиваются неправильно, последний плагин содержит команды для изменения окончаний строки:

Sublime Text 2 commands

Ответ 2

Если в файле нет спецификации и нет "интересных символов" в количестве текста, на которое смотрит file, file делает вывод, что это ASCII ISO-646 - строгий подмножество UTF-8. Вы можете обнаружить, что размещение спецификаций во всех ваших файлах побуждает все эти инструменты Windows вести себя; соглашение спецификации спецификации UTF-8, созданной в Windows. Или это может ухудшить ситуацию. Что касается x/С++, хорошо, что просто file tryin 'будет полезен и не работает. У вас javascript есть что-то в нем, похожее на С++.

Apache Tika имеет детектор кодирования; вы даже можете использовать драйвер командной строки, который поставляется вместе с ним в качестве альтернативы file. Он будет придерживаться MIME-типов, а не переходить на С++.

Ответ 3

Вместо file попробуйте пользовательскую программу, чтобы проверить только то, что вы хотите. Вот быстрый хак, в основном основанный на несколько Google показов, которые, кстати, были написаны @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.