如何在 Bash 中转换 UTF-8 特殊字符?

Mar*_*kus 8 email bash utf-8

我正在编写一个脚本,该脚本从电子邮件中提取和保存 JPEG 附件并将它们传递给 imagemagick。但是,我住在德国,电子邮件文本/主题中的特殊字符“ö”、“ä”、“ü”和“ß”很常见。

我正在用 formail 提取主题:

    SUBJECT=$(formail -zxSubject: <"$file")
Run Code Online (Sandbox Code Playgroud)

这导致:

  • =?UTF-8?Q?Meine_G=c3=bcte?=

(“Meine Güte”)甚至更糟

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

(“Schöne Grüße!”)。

我尝试将主题的一部分用作文件名和 imagemagick 文本注释,这显然不起作用。

如何在 bash 中将此 UTF-8 文本转换为带有特殊字符的文本?

提前致谢!马库斯

use*_*686 12

如何在 bash 中将此 UTF-8 文本转换为带有特殊字符的文本?

你所拥有的并不完全是“UTF-8 文本”。您实际上想要纯 UTF-8 文本作为输出,因为它是 Linux 处处用于“特殊字符”的内容。

相反,您的输入是 MIME ( RFC 2047 ) 编码的 UTF-8。“Q” 表示 Quoted-Printable 模式,“B”表示 Base64 模式。其中,Perl 的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);
}
Run Code Online (Sandbox Code Playgroud)

Oneliner(参见perldoc perlrun解释):

perl -CS -MEncode -ne 'print decode("MIME-Header", $_)'
Run Code Online (Sandbox Code Playgroud)

这可以采用任何格式作为输入:

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

Python 3 中的一个版本:

#!/usr/bin/env python3
import email.header, sys

words = email.header.decode_header(sys.stdin.read())
words = [s.decode(c or "utf-8") for (s, c) in words]
print("".join(words))
Run Code Online (Sandbox Code Playgroud)


小智 7

电子邮件主题本身就是标题,标题必须仅包含 ASCII 字符。这就是必须对 UTF-8(或任何其他非 ASCII 字符集)主题进行编码的原因。

RFC 1342 中描述了这种将非 ASCII 字符编码为 ASCII 的方法。

基本上,编码主题具有(如您已在示例中列出的)以下格式:

=?charset?encoding?encoded-text?=
Run Code Online (Sandbox Code Playgroud)

基于编码值,编码文本被解码为引用可打印 (Q) 或 base64 (B)。

要获得人类可读的形式,您需要将主题标头值的编码文本部分传递给对其进行解码的程序。我相信有一些独立的命令可以做到这一点(uudecode),但我更喜欢使用 Perl one-liners:

对于引用打印:

perl -pe 'use MIME::QuotedPrint; $_=MIME::QuotedPrint::decode($_);'
Run Code Online (Sandbox Code Playgroud)

对于 base64:

perl -pe 'use MIME::Base64; $_=MIME::Base64::decode($_);'
Run Code Online (Sandbox Code Playgroud)

确保您只传递编码文本部分而不是整个主题标题值。