本帖最后由 buyiyang 于 2023-9-19 20:28 编辑
for语句有这么一种用法FOR /F ["options"] %variable IN ('command') DO command [command-parameters]COPY 但当单引号中的command有一些特殊符号时,要用^转义,比如常用的管道符:for /f "delims=" %i in ('dir /b ^| find "123"') do echo,%iCOPY 还可以改为加上引号for /f "delims=" %i in ('"dir /b | find "123""') do echo,%iCOPY cmd /c也有类似情况。 | 如果指定了 /C 或 /K,则会将该开关之后的命令行的剩余部分作为一个命令行处理。 | | 其中,会使用下列逻辑处理引号(")字符: | | | | 1. 如果符合下列所有条件,则会保留命令行上的引号字符: | | | | - 不带 /S 开关 | | - 正好两个引号字符 | | - 在两个引号字符之间无任何特殊字符,特殊字符指下列字符: &<>()@^| | | - 在两个引号字符之间至少有一个空格字符 | | - 在两个引号字符之间的字符串是某个可执行文件的名称。 | | | | 2. 否则,老办法是看第一个字符是否是引号字符,如果是,则去掉首字符并删除命令行上最后一个引号,保留最后一个引号之后的所有文本。COPY |
也就是说cmd 的 /c 或 /k 后的部分是作为命令行字符串处理的,其中还特殊处理了引号。
我认为for /f 中单引号的'command'也是如此,还需要处理一些特殊字符,需要在双引号内或者转义,作为普通字符读取。
据我的测试,cmd /c的command中|&^需要转义,for /f的'command'中&<>()^|,=需要转义。
举两个特殊的例子: | cmd /c for /f "delims=" %i in ('dir /b ^^^| find "123"') do echo,%i | | for /f "delims=" %i in ('for /f "delims=" %i in ^('dir /b ^^^| find "123"'^) do echo,%i') do echo,%iCOPY |
这两个例子有组合、嵌套,所以第二个for /f 中的命令行的|需要进行两次转义。
前面提到了,cmd 的 /c 或 /k 后的引号会进行特殊处理,cmd /c "a 1.bat" "value1" "value2"COPY 像这种情况就会去掉首尾两个引号,导致出错,可以这样解决: | cmd /c "a 1.bat" value1 value2 | | cmd /c ""a 1.bat" value1" value2 | | cmd /c ""a 1.bat" "value1" "value2"" | | cmd /c ,"a 1.bat" "value1" "value2"COPY |
参考前面的的帮助就能解决。
而 for /f 同样会以类似的逻辑去掉引号,应该这样解决: | for /f %i in ('"a 1.bat" value1 value2') do echo,%i | | for /f %i in ('""a 1.bat" "value1" "value2""') do echo,%iCOPY |
更新补充一下,
1、作为命令行字符串处理的部分实际上是开一个子程序,会再进行一次“预处理”(变量扩展和处理特殊字符),和大家比较常用的call echo %%a%%实现变量嵌套一样,结果是c。 | set a=b | | set b=c | | for /f %%i in ('echo %%a%%') do echo,%%iCOPY |
2、在输出文本时,for /f "delims=" %%i in ("1.txt") do echo,%%i无法输出空行,实际上,for语句执行do语句的依据就是索引变量%%i,
当索引变量为空时就不会执行do语句,在批处理用for /f从wmic的结果中正确取值中有对这一特性的运用, | for /f "tokens=2" %%i in ('wmic process where "Name='WMIC.exe'" get Caption^,ExecutablePath') do set "p=%%i" | | echo %p%COPY |
某些行只有一个多余的回车字符,当行只有一个字段时,而%%i被赋的值是第二个字段,为空,所以该轮循环的do不会执行,这样回车字符就被过滤了。 |