FOR 循环空间和处理
Posted
技术标签:
【中文标题】FOR 循环空间和处理【英文标题】:FOR loop spaces and handling 【发布时间】:2016-10-21 23:52:29 【问题描述】:我有一个列出所有服务的批处理脚本,采用 BINARY_PATH,删除任何包含 c"\windows" 的行并提供 BINARY_PATHS 列表。
我们的想法是将该列表传递给 ICACLS,以确定对每个可执行文件设置的权限。
我遇到的问题是一些 BINARY_PATHS 包含前导和尾随“。 所以我不得不通过在我的 for /f 语句中添加 delims=" 来解决这个问题。
下面是输出到 ECHO 的批处理文件
for /f "tokens=2" %%n in ('sc query state^= all ^| findstr SERVICE_NAME') do (
for /f "delims=: tokens=1*" %%r in (
'sc qc "%%~n" ^| findstr BINARY_PATH_NAME'
) do (
for /f tokens^=1-2^ delims^=^" %%x in ('echo %%~s^| findstr /V /I "c:\windows\system32"') do (
echo "%%~x%%~y"
)
)
)
ECHO 输出如下 - 一个很好的干净列表,它看起来与前导空格分开
" C:\Windows\Microsoft.NET\Framework\v2.0.50727\aspnet_state.exe"
" C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorsvw.exe"
" C:\Windows\Microsoft.Net\Framework\v3.0\WPF\PresentationFontCache.exe"
" C:\Windows\Microsoft.NET\Framework\v3.0\Windows Communication Foundation\infoc
ard.exe"
" C:\Windows\Microsoft.NET\Framework\v3.0\Windows Communication Foundation\SMSvc
Host.exe"
" C:\Program Files\Photodex\ProShow Producer\ScsiAccess.exe"
" C:\Windows\servicing\TrustedInstaller.exe"
" C:\Program Files\VMware\VMware Tools\vmtoolsd.exe"
当我尝试将输出传递给不带前导和尾随 " 的 icacls 时,它会崩溃,因为某些 PATH 中有空格。
ICACLS 批处理文件:
for /f "tokens=2" %%n in ('sc query state^= all ^| findstr SERVICE_NAME') do (
for /f "delims=: tokens=1*" %%r in (
'sc qc "%%~n" ^| findstr BINARY_PATH_NAME'
) do (
for /f tokens^=1-2^ delims^=^" %%x in ('echo %%~s ^| findstr /V /I "c:\windows\system32"') do (
icacls %%~x%%~y
)
)
)
ICACLS 批处理的一些输出:
C:\Windows\Microsoft.Net\Framework\v3.0\WPF\PresentationFontCache.exe NT SERVICE
\TrustedInstaller:(F)
BUILTIN\Ad
ministrators:(RX)
NT AUTHORI
TY\SYSTEM:(RX)
BUILTIN\Us
ers:(RX)
Successfully processed 1 files; Failed processing 0 files
Invalid parameter "Communication"
Invalid parameter "Communication"
Invalid parameter "Files\Photodex\ProShow"
C:\Windows\servicing\TrustedInstaller.exe NT SERVICE\TrustedInstaller:(F)
BUILTIN\Administrators:(RX)
NT AUTHORITY\SYSTEM:(RX)
BUILTIN\Users:(RX)
Successfully processed 1 files; Failed processing 0 files
Invalid parameter "Files\VMware\VMware"
有什么想法吗?
【问题讨论】:
最外面的for /f
循环使用变量%%n
,最里面的循环也隐含地使用变量%%n
,因为%%m
和tokens=1-2
选项;虽然它有效,但我建议对最内层循环使用不重叠的变量(例如,%%x
,以及%%y
)。要删除前导和尾随""
,您不需要delims^=^"
选项;只需声明for /f "delims=" %%x in ('echo %%~s') do echo %%~x
(~
修饰符删除引号)...
问题更多的是前导和尾随空格而不是“”。
您的意思是前后双引号外部的前导/尾随空格?据我所见,echo %%~s ^| findstr ...
部分可以导致 trailing 空格,可以通过删除(转义)管道之前的空格来避免这种情况,例如echo %%~s^| findstr ...
;我看不到 leading 空格的来源,但如果有,您可以通过 for /F "tokens=*" %%l in (...) do echo %%l
删除它们(记住默认分隔符 space 和 tab i>)...
谢谢,抱歉我的解释可能不正确。如果您查看代码,我必须在输出周围添加“”以使其与 icacls 一起使用,此时有一个前导空格“c:\path\path\executable”
啊,我明白了!中间的for /f
循环是前导空格的来源;为避免这种情况,请将其更改为:for /f "tokens=1* delims=: " %%r
;我只是交换了tokens
和delims
选项,并将 space 定义为最后一个分隔符(只有当它是选项字符串中的最后一个字符时,空格才被用作分隔符);这避免了前导空格并且可以工作,因为第一个标记本身不包含空格...
【参考方案1】:
在引号之间括起来路径是绝对正确的,以避免出现空格问题。
但是,我不会删除也包含在""
中的前导和尾随空格,而是尝试不生成它们,而不是稍后消除它们。
前导空格来自中间for /f
循环:
for /f "delims=: tokens=1*" %%r in ('sc qc "%%~n" ^| findstr BINARY_PATH_NAME') do ( ... )
过滤后的sc qc
命令产生如下输出行:
BINARY_PATH_NAME : C:\Windows\System32\spoolsv.exe BINARY_PATH_NAME : "C:\Program Files\iPod\bin\iPodService.exe"
使用您的 "delims=: tokens=1*"
选项,分隔符 (:
) 之后的部分包含前导空格。
为了克服这个问题,添加空格作为另一个分隔符,但要确保它是选项字符串中的最后一个字符:"tokens=1* delims=: "
。
尾部空格来自echo
内部循环解析的管道for /f
:
for /f tokens^=1-2^ delims^=^" %%x in ('echo %%~s ^| findstr /V /I "c:\windows\system32"') do ( ... )
echo %%~s
和 ^|
之间的空格也包含在输出中。因此,只需将其删除。
不需要定义选项字符串tokens^=1-2^ delims^=^"
,因为for /f
循环无论如何都不应该接收任何要解析的引号(由于%%~s
中的~
修饰符),所以"delims="
就足够了。因此仅在循环体中使用%%~x
。
此外,如果%%~s
为空,我建议写echo(%%~s
而不是echo %%~s
以避免ECHO is on/off.
消息(尽管这永远不会发生)。
另一个问题是sc query state= all
检索到的服务名称也可能包含空格;例如:
SERVICE_NAME: iPod Service
所以对于外部for /f
循环,"tokens=2"
选项不是最优的;在上面的例子中,只会返回iPod
。因此将其更正为"tokens=1*"
并忽略forst 令牌。
由于只搜索文字字符串,我将findstr
实例替换为find
,除了最后一个,因为find
仅支持单个搜索字符串。
我在剩余的 findstr
实例中添加了另一个搜索字符串,以便同时覆盖还存在目录 C:\Windows\SysWOW64
的 64 位 Windows 系统,我假设您也想过滤掉它。
这里是固定代码:
@echo off
for /f "tokens=1*" %%m in ('sc query state^= all ^| find "SERVICE_NAME"') do (
for /f "tokens=1* delims=: " %%r in ('sc qc "%%~n" ^| find "BINARY_PATH_NAME"') do (
for /f "delims=" %%x in ('echo(%%~s^| findstr /L /V /I /C:"%SystemRoot%\System32" /C:"%SystemRoot%\SysWOW64"') do (
ECHO icacls "%%~x"
)
)
)
测试成功后去掉大写的ECHO
,以便执行icacls
命令行。
【讨论】:
以上是关于FOR 循环空间和处理的主要内容,如果未能解决你的问题,请参考以下文章