Windows cmd.exe 命令传递 Perl 系统函数在某些情况下需要双引号吗?
Posted
技术标签:
【中文标题】Windows cmd.exe 命令传递 Perl 系统函数在某些情况下需要双引号吗?【英文标题】:Windows cmd.exe command passed Perl system function needs double quotes in some cases? 【发布时间】:2021-06-29 01:29:23 【问题描述】:Windows cmd.exe 命令 'type \Test\hello.txt' 必须用双引号引起来,以便 Perl system() 函数正确执行它。我没有在 https://perldoc.perl.org/functions/system 或 https://perldoc.perl.org/perlport#system 找到此文档 - Windows 上的双引号要求是否记录在任何地方?
以下示例代码演示了在 Windows 10 Pro 服务器版本 2004(OS Build 19041.867)的 Windows 命令提示符窗口中使用命令 perl \my\perl\perlsystest
运行时出现的问题,Perl 级别为 v5.26.3
$cmd='type \Test\hello.txt' ; # Set Windows DOS command to be executed
system('ECHO '.$cmd) ; # Display command to be executed
system($cmd) == 0 # Execute command - note "\Test\hello.txt not found" error but with $? == 0
or die "system(\"$cmd\") failed: $?!" ;
if ($? == -1) print "system(\"$cmd\") failed to execute: $!!\n"
elsif ($? & 127) printf "system(\"$cmd\") child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without' ; exit
elsif ($? != 0) printf "system(\"$cmd\") child exited with value %d\n", $? ; exit
$cmd='"'.$cmd.'"' ; # Surround command string in double quotes
system('ECHO '.$cmd) ; # Display command to be executed
system($cmd) == 0 # Execute command - note that command succeeds
or die "system(\"$cmd\") failed: $?!" ;
if ($? == -1) print "system(\"$cmd\") failed to execute: $!!\n"
elsif ($? & 127) printf "system(\"$cmd\") child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without' ; exit
elsif ($? != 0) printf "system(\"$cmd\") child exited with value %d\n", $? ; exit
$cmd='type \Test\10hello.txt' ; # Set Windows DOS command to be executed
system('ECHO '.$cmd) ; # Display command to be executed - note that "type \Teshello.txt" is echoed
system($cmd) == 0 # Execute command - note "\Test\hello.txt not found" error but with $? == 0
or die "system(\"$cmd\") failed: $?!" ;
if ($? == -1) print "system(\"$cmd\") failed to execute: $!!\n"
elsif ($? & 127) printf "system(\"$cmd\") child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without' ; exit
elsif ($? != 0) printf "system(\"$cmd\") child exited with value %d\n", $? ; exit
system('"ECHO '.$cmd).'"' ; # Display command to be executed (with ECHO command in double quotes)
$cmd='"'.$cmd.'"' ; # Surround command string in double quotes
system($cmd) == 0 # Execute command
or die "system(\"$cmd\") failed: $?!" ;
if ($? == -1) print "system(\"$cmd\") failed to execute: $!!\n"
elsif ($? & 127) printf "system(\"$cmd\") child died with signal %d, %s coredump\n",
($? & 127), ($? & 128) ? 'with' : 'without' ; exit
elsif ($? != 0) printf "system(\"$cmd\") child exited with value %d\n", $? ; exit
【问题讨论】:
我无法在 Windows 10 Pro 上使用我的 Perl 5.30 重现(脚本正常执行,没有任何错误)。 Win32::ShellQuote 很有用。 @Mofi 和 @ikegami,感谢您的 cmets。合成这些 cmets:当处理system()
调用时,Perl 向 Windows 发送一个命令,该命令通过将传递给 system() 调用的参数附加到 sh
变量(来自 Perl Config.pm)中的值来构建。在我的 Windows 10 上,perl -V:sh
显示 sh='cmd /x /c'
,因此当使用 $cmd='type \Test\hello.txt'
调用 system($cmd)
时,声称 Perl 将导致 Windows 运行命令 cmd /x /c type \Test\hello.txt
。
但这并不完全正确,因为我的 Windows 10 上的 cmd /x /c type \Test\hello.txt
正确键入了 \Test\hello.txt
文件,但是当使用 $cmd='type \Test\hello.txt'
调用 system($cmd)
时,system($cmd)
调用会引发错误消息\Test\hello.txt not found
但返回 $?=0
。
感谢@Dada,他及时评论说:“我无法在 Windows 10 Pro 上使用我的 Perl 5.30 进行复制(脚本正常执行而没有任何错误)”。
【参考方案1】:
你给system 的任何东西都必须适合处理命令的东西。原问题的 cmets 应该变成答案。
system
文档指向exec,它还说:
当参数通过系统 shell 执行时,结果受制于其怪癖和功能。有关详细信息,请参阅 perlop 中的“
STRING
”。
这也指向perlop 中用于反引号的条目:
如何评估该字符串完全取决于系统上的命令解释器。在大多数平台上,如果您希望按字面意思对待 shell 元字符,则必须保护它们。这在实践中很难做到,因为不清楚如何转义哪些字符。
Perl 在这里没有解决单个系统,因为它支持的系统太多了(即使使用这些系统的每个人都已经消失了)。
你在那里贴了一堵文字墙,我不得不重写它来看看你在做什么。与其重复相同的代码,一个子程序(有一些合理的格式)对读者很礼貌:)
my @commands = (
'type \Test\hello.txt',
q("type \Test\hello.txt")
'type \Test\10hello.txt',
);
foreach my $command ( @commands )
try_it( $command );
sub try_it
my( $cmd ) = @_;
system('ECHO '.$cmd);
system($cmd) == 0 # Execute command
or die qq(system("$cmd") failed: $?!) ;
if ($? == -1)
print qq(system("$cmd") failed to execute: $!!\n);
elsif ($? & 127)
printf qq(system("$cmd") child died with signal %d, %s coredump\n),
($? & 127), ($? & 128) ? 'with' : 'without' ;
elsif ($? != 0)
printf qq(system("$cmd") child exited with value %d\n), $? ;
【讨论】:
以上是关于Windows cmd.exe 命令传递 Perl 系统函数在某些情况下需要双引号吗?的主要内容,如果未能解决你的问题,请参考以下文章
Windows的idea的Terminal替换为git bash(默认是Windows的cmd.exe命令行)