我知道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
答案 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{}
。