gpt4 book ai didi

windows - Strawberry Perl——默认情况下在哪里进行编码转换?

转载 作者:可可西里 更新时间:2023-11-01 10:02:36 26 4
gpt4 key购买 nike

基本上,我编写了一个 Perl 脚本,为 Powershell 创建一个编码命令并尝试运行它。在对其进行 base64 编码之前,我必须将命令字符串显式转换为 utf-16。我想知道为什么这就是我必须做的全部才能使脚本正常工作的原因。 Windows* 上的 Perl 在运行与控制台和文件系统交互的“普通”程序时默认执行哪些转换?例如,是否转换了 argv? stdin/stdout 是否转换?文件 IO 是否经过转换?

✱ 特别是 Strawberry Perl 发行版,以防 ActivePerl 做一些不同的事情


我正在尝试编写调用许多 PowerShell 片段并依赖 Strawberry Perl 分发的 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
}

然后运行它。这是在 powershell 窗口中运行 perl 脚本的...标准输出 channel (?)的输出。

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 相关的转换?

最佳答案

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)。您需要向 print/printf/say< sup>[1],你将从readline/read/readpipe接收到一串字节。

您可以在打开文件时提供编码/解码层。

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

您可以通过 open 提供默认编码/解码层语用。

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

在这两种情况下,您现在都需要向 print/printf/say 提供一串 Unicode 代码点,然后您将类似地从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 对字符串进行编码。

关于windows - Strawberry Perl——默认情况下在哪里进行编码转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52941626/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com