Как в Perl передать аргументы Unicode внешним командам?

Основной причиной этого вопроса является моя попытка написать тесты для нового модуля обработки параметров/аргументов ( OptArgs) для Перл. Это, конечно, включает разбор @ARGV, который я делаю на основе ответов на этотвопрос. Это прекрасно работает в системах, где определен I18N::Langinfo::CODESET[1].

В системах, где langinfo(CODESET)недоступен, я хотел бы, по крайней мере, сделать все возможное, основываясь на наблюдаемом поведении. Однако мои тесты до сих пор показывают, что в некоторых системах я даже не могу правильно передать юникод-аргумент внешнему скрипту.

Мне удалось запустить что-то вроде следующего в различных системах, где «test_script» — это Perl-скрипт, который просто выполняет print Dumper(@ARGV):

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, либо оболочка, но в отличие от файловых дескрипторов (где я могу binmode их для кодирования) я не знаю, как убедиться, что он делает то, что я хочу.То же самое с system(). Итак, мой вопрос в том, что я не делаю правильно выше? В противном случае, чем отличается Perl, оболочка или среда в OpenBSD и Solaris?

[1] На самом деле я пока думаю, что это только Linux по результатам тестеров CPAN.

Обновление(x2):В настоящее время я прохожу через настройки cpantester, чтобы проверить гипотезу Шверна:

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();

Я опубликую результаты на различных системах, когда они поступят. Любые комментарии относительно действительности и или правильности этого будут оценены. Обратите внимание, что он непредназначен для проверки. Целью вышеизложенного является возможность сравнить то, что получено в разных системах.

Резолюция : Реальная основная проблема оказывается чем-то, что не рассматривается ни в моем вопросе, ни в ответе Шверна ниже. Я обнаружил, что на некоторых машинах cpantesters установлена/доступна только локаль ascii. Я не должен ожидать, что любая попытка передать символы UTF-8 программам в среде такого типа сработает. Итак, в конце концов моя проблема заключалась в неверных условиях тестирования, а не в неверном коде.

До сих пор я не видел ничего, что указывало бы на то, что оператор qxили модуль utf8::allкаким-либо образом влияют на то, как параметры передаются внешним программам. Критически важным компонентом являются переменные окружения LANGи/или LC_ALL, чтобы сообщить внешней программе, в какой локали они работают.

Между прочим, мое первоначальное утверждение, что мой код работал на всех системах, где I18N::Langinfo::CODESET определен неправильно.

7
задан Community 23 May 2017 в 12:29
поделиться