Strawberry Perl - где преобразования кодирования выполняются по умолчанию? - PullRequest
0 голосов
/ 23 октября 2018

По сути, я написал Perl-скрипт, который создает закодированную команду для Powershell и пытается ее запустить.Мне пришлось явно преобразовать командную строку в utf-16 перед ее кодировкой base64.Мне интересно, почему это все Мне нужно было заставить скрипт работать.Какие преобразования выполняет Perl в Windows * по умолчанию при запуске «обычной» программы, которая взаимодействует с консолью и, возможно, с файловой системой?Например, конвертируется ли argv?Преобразован ли stdin / stdout?Проходит ли файловый ввод-вывод преобразование?

, в частности, дистрибутив Strawberry Perl в случае, если ActivePerl делает что-то другое


Я пытаюсь написать сценарий Perl, который вызывает много PowerShellфрагментируется и зависит от дистрибутива Strawberry Perl.

PowerShell, довольно удобно, имеет флаг -encodedCommand, который принимает строку в кодировке base64, а затем обрабатывает ее.Это полезно для избежания проблем, связанных с цитированием.

Я попробовал самое простое, что могло бы сработать.

// powersheller.pl

#! /usr/bin/env perl

use strict;
use warnings;

use MIME::Base64;
use Encode qw/encode decode/;

use vars ('$powershell_command');

sub run_powershell_fragment {
    my ($contents) = @_;
    my $encoded = encode_base64($contents);
    printf "encoded: %s\n", $encoded;
    return `powershell.exe -noprofile -encodedCommand $encoded`;
}

printf "%s\n---\n", run_powershell_fragment($powershell_command);

BEGIN {
$powershell_command = <<EOF
echo "hi"   
EOF
}

И запустил его.Вот вывод ... стандартных выходных каналов (?) При запуске сценария perl в окне powershell.

PS C\...> perl .\powersheller.pl
encoded: ZWNobyAiaGkiCQo=

Redundant argument in printf at .\powersheller.pl line 18.
?????? : The term '??????' is not recognized as the name of a cmdlet, function, script file, or operable program.

---

Это выглядело как проблема с кодировкой.Я догадывался, что Perl использует что-то похожее на utf-8 по умолчанию, и powershell ожидал utf16-le или аналогичный.

sub run_powershell_fragment {
    my ($contents) = @_;
    my $utf16_le_contents = encode("utf-16le", $contents);
    my $encoded = encode_base64($utf16_le_contents);
    printf "encoded: %s\n", $encoded;
    return `powershell.exe -noprofile -encodedCommand $encoded`;
}

Технически, использование "ucs-2le" также работает.Я не знаю, что подходит.

В любом случае, все вместе, программа работает, как и ожидалось, со вставленным дополнительным преобразованием.

PS C:\...> perl .\powersheller.pl
encoded: ZQBjAGgAbwAgACIAaABpACIACQAKAA==

hi

---

Почему это было все, что мне нужно было сделать?Связывает ли Perl конвертации с argv и stdout & c?

1 Ответ

0 голосов
/ 23 октября 2018

qx`` не выполняет преобразование.Ожидается, что команда будет закодирована с использованием системной кодовой страницы ANSI, поскольку она будет передана без изменений в CreateProcessA или аналогичную. [1]

use Encode qw( encode );
use Win32  qw( );

my $cmd_ansi = encode("cp".Win32::GetACP(), $cmd);
`$cmd_ansi`

Конечно, если командасодержит только символы ASCII, кодирование является спорным.


Аналогично, значение в @ARGV не было декодировано.Они получены из системы, закодированной с использованием системной кодовой страницы ANSI.

use Encode qw( decode );
use Win32  qw( );

my @decode_argv = map { decode("cp".Win32::GetACP(), $_) } @ARGV;

Конечно, если аргументы содержат только символы ASCII, декодирование является спорным.


По умолчаниюдескрипторы файлов не выполняют никакого кодирования или декодирования, за исключением преобразования CRLF ⇔ LF (CRLF ⇒ LF при чтении, LF ⇒ CRLF при записи).Ожидается, что вы предоставите строку байтов (строку символов со значениями в 0..255) до print / printf / say [1] , и вы получите строкубайтов из readline / read / readpipe.

Вы можете предоставить слой кодирования / декодирования при открытии файла.

open(my $fh, '>:encoding(UTF-8)', $qfn)

Вы можете указать кодировку по умолчанию/ декодирующий слой с помощью open pragma.

use open ':encoding(UTF-8)';
open(my $fh, '>', $qfn)

В обоих случаях вам теперь нужно будет предоставить строку кодовых точек Unicode до print / printf / say и вы также получите строку байтов от readline / read / readpipe.

Я не уверен, что лучше для STDIN / STDOUT / STDERR, но вы могли бы начать сследующее:

use Win32 qw( );
my ($in_enc, $out_enc);
BEGIN {
   $in_enc  = "cp".Win32::GetConsoleCP();
   $out_enc = "cp".Win32::GetConsoleOutputCP();
   binmode STDIN,  ":encoding($in_enc)";
   binmode STDOUT, ":encoding($out_enc)";
   binmode STDERR, ":encoding($out_enc)";
}

Вы должны использовать UTF-16le, а не UCS-2le.


  1. Если вы предоставляете строку, содержащую не байты (символы вне 0..255), Perl предполагает, что вы намеревались закодировать строку, используя UTF-8.Он будет предупреждать («широкий символ») и кодировать строку, используя utf8.
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...