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