在Perl中如何将unicode参数传递给外部命令?

时间:2012-06-20 01:36:48

标签: perl unicode utf-8 solaris openbsd

此问题的根本原因是我尝试为Perl编写新选项/参数处理模块(OptArgs)的测试。这当然涉及根据this问题的答案解析我正在做的@ARGV。这适用于定义了I18N :: Langinfo :: CODESET的系统[1]。

langinfo(CODESET)不可用的系统上,我希望至少根据观察到的行为尽最大努力。但是到目前为止我的测试表明,有些系统我甚至无法正确地将 unicode参数传递给外部脚本。

我设法在各种系统上运行类似下面的内容,其中“test_script”是仅执行print Dumper(@ARGV)的Perl脚本:

use utf8;
my $utf8   = '¥';
my $result = qx/$^X test_script $utf8/;

我发现在FreeBSD上,test_script接收可以解码为Perl内部格式的字节。但是在OpenBSD和Solaris上,test_script似乎得到的字符串"\x{fffd}\x{fffd}"只包含unicode替换字符(两次?)。

我不知道qx运算符背后的机制。我认为它要么是exec,要么是shell,但不像文件句柄(我可以将它们用于编码的binmode)我不知道如何确保它做我想要的。与system()相同。所以我的问题是我上面没有正确做什么?否则与Perl或OpenBSD和Solaris上的shell或环境有什么不同?

[1]实际上我认为到目前为止根据CPAN测试人员的结果只有Linux。

更新(x2):我目前通过cpantester的设置运行以下方法来测试Schwern的假设:

use strict;
use warnings;
use Data::Dumper;

BEGIN {
    if (@ARGV) {
        require Test::More;
        Test::More::diag( "\npre utf8::all: "
              . Dumper( { utf8 => $ARGV[0], bytes => $ARGV[1] } ) );
    }
}

use utf8;
use utf8::all;

BEGIN { 
    if (@ARGV) {
        Test::More::diag( "\npost utf8::all: "
              . Dumper( { utf8 => $ARGV[0], bytes => $ARGV[1] } ) );
        exit;
    }
}

use Encode;
use Test::More;

my $builder = Test::More->builder;
binmode $builder->output,         ':encoding(UTF-8)';
binmode $builder->failure_output, ':encoding(UTF-8)';
binmode $builder->todo_output,    ':encoding(UTF-8)';

my $utf8  = '¥';
my $bytes = encode_utf8($utf8);

diag( "\nPassing: " . Dumper( { utf8 => $utf8, bytes => $bytes, } ) );

open( my $fh, '-|', $^X, $0, $utf8, $bytes ) || die "open: $!";
my $result = join( '', <$fh> );
close $fh;

ok(1);
done_testing();

我会在各种系统上发布结果。任何关于此的有效性和正确性的评论都会受到赞赏。请注意,旨在成为有效的测试。上述目的是能够比较不同系统上收到的内容。

决议:真正的潜在问题在我的问题中未得到解决,Schwern的答案也未在下面解决。我发现一些cpantesters机器只安装了/可用的ascii语言环境。我不应该期望任何尝试将UTF-8字符传递给此类环境中的程序才能工作。所以最后我的问题是无效的测试条件,而不是无效的代码。

到目前为止,我没有看到任何内容表明qx运算符或utf8::all模块对参数传递给外部程序的方式有任何影响。关键组件似乎是LANG和/或LC_ALL环境变量,用于通知外部程序它们正在运行的语言环境。

顺便说一下,我的原始断言是我的代码在所有定义了I18N :: Langinfo :: CODESET的系统上运行是不正确的。

1 个答案:

答案 0 :(得分:2)

qx调用shell,可能会干扰。

为避免这种情况,请使用utf8::all打开所有Perl Unicode voodoo。然后使用open函数打开程序的管道,避免使用shell。

use utf8::all;
my $utf8   = '¥';

open my $read_from_script, "-|", "test_script", $utf8;
print <$read_from_script>,"\n";