基本上,我编写了一个Perl脚本,该脚本为Powershell创建了一个编码命令并尝试运行它。在base64编码之前,我必须将命令字符串显式转换为utf-16。我想知道为什么为什么要全部使脚本正常工作。 Windows *上的Perl默认在与控制台甚至是文件系统交互的“普通”程序的运行中执行哪些转换?例如,argv是否已转换? stdin / stdout是否已转换?文件IO是否会进行转换?
✱特别是草莓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
}
然后运行它。这是在powershell窗口中运行perl脚本的...标准输出通道(?)的输出。
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相关的转换吗?
答案 0 :(得分:3)
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
[1] 提供一个字节字符串(值在0..255中的字符串)。 ,您将从readline
/ read
/ readpipe
中收到一串字节。
打开文件时,您可以提供一个编码/解码层。
open(my $fh, '>:encoding(UTF-8)', $qfn)
您可以通过open编译指示提供默认的编码/解码层。
use open ':encoding(UTF-8)';
open(my $fh, '>', $qfn)
在两种情况下,您现在都需要向print
/ printf
/ say
提供一个Unicode代码点字符串,并且类似地,您将从{ {1}} / readline
/ read
。
我不确定STDIN / STDOUT / STDERR的最佳选择,但是您可以从以下内容开始:
readpipe
您应该使用UTF-16le而不是UCS-2le。