Вопрос: Как преобразовать специальные символы UTF-8 в Bash?


Я пишу сценарий, который извлекает и сохраняет JPEG-прикрепления из электронных писем и передает их в imagemagick. Тем не менее, я живу в Германии, и специальные символы в тексте / теме по электронной почте, как «ö», «ä», «ü» и «ß», довольно распространены.

Я извлекаю тему с помощью formail:

    SUBJECT=$(formail -zxSubject: <"$file")

и это приводит к:

  • =? UTF-8? Q? Meine_G = с3 = bcte? =

(«Meine Güte») или еще хуже

  • =? UTF-8? B? U2Now7ZuZSBHcsO8w59lIQ ==? =

(«Schöne Grüße!»).

Я пытаюсь использовать часть темы в качестве имени файла и как текстовую аннотацию imagemagick, которая, очевидно, не работает.

Как преобразовать этот текст UTF-8 в текст со специальными символами в bash?

Заранее спасибо! Markus


4
2017-09-12 23:16


Источник


Также отсутствуют пробелы между словами и пунктуацией :( - Markus


Ответы:


Как преобразовать этот текст UTF-8 в текст со специальными символами в bash?

У вас нет довольно «Текст UTF-8». Вы на самом деле хотеть простой текст UTF-8 как вывод, поскольку это то, что Linux использует для «специальных символов» повсюду.

Вместо этого ваш вход - MIME (RFC 2047) кодирует UTF-8. «Q» обозначает режим Quoted-Printable, а «B» обозначает режим Base64. Среди прочего, Perl's Encode :: MIME :: Header может использоваться для декодирования обоих:

#!/usr/bin/env perl
use open qw(:std :utf8);
use Encode qw(decode);

while (my $line = <STDIN>) {
        print decode("MIME-Header", $line);
}

Oneliner (см. perldoc perlrun для объяснения):

perl -CS -MEncode -ne 'print decode("MIME-Header", $_)'

Это может принимать любой формат в качестве входных данных:

$ echo "Subject: =?UTF-8?Q?Meine_G=c3=bcte?=, \
                 =?UTF-8?B?U2Now7ZuZSBHcsO8w59lIQ==?=" | perl ./decode.pl
Subject: Meine Güte, Schöne Grüße!

6
2017-09-13 00:10



Один-лайнер не работал для меня. (см. @blami). Но код PL работал нормально. Когда я использовал последний скрипт, часть Base64 не была закодирована вообще. Даже когда я пробовал только эту часть. Ваше объяснение тоже помогло мне. - Markus


Сама тема электронной почты - заголовок, а заголовки должны содержать только символы ASCII. Вот почему кодировка UTF-8 (или любого другого не-ASCII-кодировки) должна быть закодирована.

Этот способ кодирования символов, отличных от ASCII, в ASCII описан в RFC 1342.

В принципе, закодированный субъект имеет (как вы уже указали в своих примерах) следующий формат:

=?charset?encoding?encoded-text?=

На основе значения кодирования кодируется-текст декодируется либо как цитируемый-печатный (Q), либо как base64 (B).

Чтобы получить удобочитаемую форму, вам необходимо передать часть кодированного текста заголовка объекта, чтобы его декодировать. Я считаю, что для этого есть некоторые автономные команды (uudecode), но я предпочитаю использовать однострочные Perl:

Для цитируемых:

perl -pe 'use MIME::QuotedPrint; $_=MIME::QuotedPrint::decode($_);'

и для base64:

perl -pe 'use MIME::Base64; $_=MIME::Base64::decode($_);'

Убедитесь, что вы передали только часть кодированного текста, а не целое значение заголовка объекта.


5
2017-09-13 00:10



Спасибо за ваш комментарий! Я многому научился из вашего подробного объяснения. Тем не менее, я не мог заставить однострочные лайнеры работать нормально (в замазке на малине pi). Но я уверен, что это только из-за моих слабых навыков linux. Я использовал echo "=? UT ...:" | perl ... и результат был «=? UTF-8? Q? Meine_Güte?». Только «ü» был переведен. Приведенный скрипт @grawity предоставил хорошие результаты. - Markus