在 Windows 上将 UTF-8 参数传递给 Perl 中的命令

问题描述 投票:0回答:1

我正在尝试为 Perl 脚本构建一个模板,以便它们至少可以使用 UTF-8 正确完成大部分基本操作,并且在 Linux 和 Windows 机器上同样可以正常工作。

我有一段时间特别忽略了一件事:将 UTF-8 字符串作为参数传递给系统命令的困难。在我看来,在参数到达 shell 之前,没有办法不对其进行双重 UTF-8 编码(也就是说,我知道有一个层忽略命令及其参数已经正确地进行了 UTF-8 编码,将其视为 Latin-1 或类似的东西,并再次将其编码为 UTF-8)。我找不到一种方法来彻底避免这一层编码。

采用此脚本:

#!/usr/bin/perl

use v5.14;

use utf8;
use feature 'unicode_strings';
use feature 'fc';
use open ':std', ':encoding(UTF-8)';
use strict;
use warnings;
use warnings FATAL => 'utf8';

use constant IS_WINDOWS => $^O eq 'MSWin32';

# Set proper locale
$ENV{'LC_ALL'} = 'C.UTF-8';

# Set UTF-8 code page on Windows
if (IS_WINDOWS) {
  system("chcp 65001 > nul 2>&1");
};

# Use Win32::Unicode::Process on Windows
if (IS_WINDOWS) {
  eval {
    require Win32::Unicode::Process;
    Win32::Unicode::Process->import;
  };
  if ($@) {
    die "Could not load Win32::Unicode::Process: $@";
  };
};


# Show the empty directory
print "---\n" . `ls -1 system*` . "---\n";

my $utf = "test-тест-מבחן-परीक्षण-😊-𝓽𝓮𝓼𝓽";

# Works fine on Linux but not on Windows
print "System (touch) exit code: " . system("touch system-$utf > touch-system.txt 2>&1") . "\n";
print "System (echo) exit code: " . system("echo system-$utf > echo-system.txt 2>&1") . "\n";

if (IS_WINDOWS) {
  # Works fine on Windows
  print "SystemW (touch) exit code: " . systemW("touch systemW-$utf > touch-systemW.txt 2>&1") . "\n";
  print "SystemW (echo) exit code: " . systemW("echo systemW-$utf > echo-systemW.txt 2>&1") . "\n";
};

# Show the directory with the new the files
print "---\n" . `ls -1 system*` . "---\n";

exit;

在 Linux 上,一切都很好:使用

touch
system()
创建的文件具有 UTF-8 编码的文件名,并且使用
echo
创建的文件内容是正确的 UTF-8 编码。

然而,我发现没有办法让相同的代码在 Windows 上正确运行。脚本的输出是这样的:

---
---
System (touch) exit code: 0
System (echo) exit code: 0
SystemW (touch) exit code: 
SystemW (echo) exit code: 
---
system-test-теÑÑ‚-מבחן-परीकà¥à¤·à¤£-😊-ð“½ð“®ð“¼ð“½
systemW-test-тест-מבחן-परीक्षण-😊-𝓽𝓮𝓼𝓽
---

如脚本所示,我可以使其工作的唯一方法是使用

Win32::Unicode::Process::systemW()
替换
system()
。文件
systemW-test-тест-מבחן-परीक्षण-😊-𝓽𝓮𝓼𝓽
已正确命名,并且
echo-systemW.txt
的内容已正确编码为 UTF-8。

我的问题是:

  1. 有没有办法避免使用

    systemW()
    并保持Linux和Windows的代码相同,但以某种方式删除这层对系统命令进行双重编码的层?换句话说,这是唯一的好方法吗?

  2. 如果这是正确的方法,我不确定如何获得反引号的类似正确行为。他们有与

    system()
    相同的问题,但我不知道如何使用
    systemW()
    捕获命令的输出,除了将其管道到临时文件中并在最后读取(当然,可能,但可能不是很好) ).

windows perl encoding utf-8
1个回答
0
投票

避免使用 systemW() 在 Linux 和 Windows 上实现统一行为:不幸的是,Windows 的 cmd.exe 并不像 Linux shell 那样原生支持 UTF-8。即使使用 chcp 65001(将控制台代码页设置为 UTF-8),也存在怪癖和不一致。出现双重编码问题是因为 Windows 上的 Perl system() 函数和反引号 (```) 内部使用 ANSI API,而这些 API 不完全尊重 UTF-8。

为了实现一致的行为,您必须使用宽字符 API,例如 Win32::Unicode::Process 中的 systemW()。 Windows 上的 Perl 标准 system() 没有直接的方法来绕过这个限制。

使用宽字符 API 处理反引号:正如您所发现的,Perl 的反引号也依赖于 ANSI API,并且没有用于捕获输出的 systemW() 的直接等效项。但是,您可以使用以下解决方法:

如您所提到的,使用临时文件进行命令输出。 或者,利用 Win32::Unicode::Process 使用宽字符 API 实现自定义反引号行为。

© www.soinside.com 2019 - 2024. All rights reserved.