运行Perl one-liners时Windows cmd如何转换命令行?

时间:2016-08-04 11:43:40

标签: windows perl shell

我知道Windows shell将可执行文件名后的整行传递给可执行文件,并且可解析它的是可执行文件的任务。 例如,

C:\Users\osiv\Desktop\>perl -e "use File::Spec; print $_.' ' foreach (File::Spec->splitdir(\"C:\\Users\\osiv\\\"));"

应该在' perl'之后传递所有字符。到%PATH%值目录中找到的perl.exe。

解释输出

C:\Users\osiv\Desktop\>perl -e "use File::Spec; print $_.' ' foreach (File::Spec->splitdir(\"C:\\Users\\osiv\\\"));"
Can't find string terminator '"' anywhere before EOF at -e line 1.

C:\Users\osiv\Desktop\>perl -e "use File::Spec; print $_.' ' foreach (File::Spec->splitdir(\"C:\\Users\\osiv\\\\"));"
Can't find string terminator '"' anywhere before EOF at -e line 1.

C:\Users\osiv\Desktop\>perl -e "use File::Spec; print $_.' ' foreach (File::Spec->splitdir(\"C:\\Users\\osiv\\\\\"));"
C: Users osiv

我期望Perl通过查找应该具有"的字符串来解析Windows shell传递的字符串。在开始和结束。我通过\"来逃避它们,并期望例如\"osiv\\\\\"));"要解析为osiv\\。但是,\"osiv\\\"));"未被解析为osiv\,那么它实际上是如何被解析的?

Explanation of cmd.exe, CreateProcess command line string metacharacters

1 个答案:

答案 0 :(得分:5)

谁在乎? exact rules are convoluted and hard to remember。{{3}}。通过在Perl one liners中不使用双引号来避免这个问题。您知道自己有'q{}qq{}

  

所有cmd的转换都是由其中一个元字符()%!^,{{1 },"<>&|特别有趣:当cmd转换命令行并看到"时,它会将"复制到新命令行,然后开始将旧命令行中的字符复制到新的,没有看到这些字符是否是元字符。此复制将继续,直到cmd到达命令行的末尾,进入变量替换,或者看到另一个"。在最后一种情况下,cmd将"复制到新命令行并恢复正常处理。这种行为差不多,但不像CommandLineFromArgvW用同一个字符做的那样;区别在于cmd不知道"序列,并且开始比我们预期的更早地解释元字符。

此外:

\"

C:\> perl -MFile::Spec::Functions=splitdir -MFile::HomeDir -we "print qq{'$_' } for splitdir home"

'C:' 'Users' 'sinan'

perl -wE "use File::Spec; print \"'$_' \" for File::Spec->splitdir( \"C:\\Users\\osiv\\\\\" )"

表示您应该省略尾随目录分隔符。

  

更好的引用方法

     

虽然'C:' 'Users' 'osiv' ''元字符无法完全保护命令行中的元字符,防止意外的shell解释,但"元字符可以。当cmd转换命令行并看到^时,它会忽略^字符本身,并将下一个字符按字面意思复制到新命令行,是否为元字符。这就是^作为行继续符的原因:它告诉cmd将后续换行符复制为自身,而不是将该换行符作为命令终止符。如果我们在参数字符串中使用^前缀每个元字符,cmd会将该字符串转换为我们要使用的字符串。

试着遵循这一点,我能想到的最好的是:

^

正如我所说,避免单行中的perl -wE ^"use File::Spec; print \^"'$_' \^" for File::Spec-^>splitdir^(\^"C:\\Users\\osiv\\\\\^"^) ^",使用"'q{}