作为学习Windows批处理编程的一种做法,我试图创建一个批处理文件,该文件将处理文件夹中的所有SCSS文件并将其编译为CSS。尝试滤除以下划线开头的所有文件时遇到了一个问题,因为这些文件是片段,仅可在@import语句中使用。
我到目前为止拥有的批处理文件是:
@echo off
SETLOCAL EnableDelayedExpansion
FOR /R "D:\Jaye\Programming\Web\Project\scss" %%G IN (*.scss) DO (
SET name=%%~nG
echo !name!
SET firstChar=!name:~0,1!
echo !firstChar!
if !firstChar! == "_" (
echo "Dont process this file"
)
)
ENDLOCAL
... \ Project \ scss文件夹包含以下四个文件:
main.scss
menus.scss
content.scss
_uiColors.scss
我得到的输出是:
content
c
main
m
menus
m
_uiColors
_
这里的重要问题是_uiColors.scss文件不会触发bat文件第9行的if语句。根据输出,我可以看到它正在按预期方式将firstChar变量设置为下划线,但是在if语句中进行比较时,并没有达到我的预期。我想知道为什么"_"=="_"
似乎评估为假(可能是类型不匹配吗?),然后我可能会尝试解决它。
谢谢
编辑(有答案):由于Mofi和Gerhard的回答,我现在可以正常工作了。多谢你们。 我遇到的问题是由于我基于以前使用其他现代语言的经验所做出的假设,因此在处理字符串时我不正确地使用引号。
答案 0 :(得分:2)
我对Symbol equivalent to NEQ, LSS, GTR, etc. in Windows batch files的回答详细说明了如何通过命令 IF 完成字符串比较,该命令包括用于比较字符串的周围的"
。因此,条件if !firstChar! == "_"
永远不会为真,因为左侧的字符串始终只是一个字符,从不以"
开头,而右侧的字符串则包含三个字符。
我建议执行此任务:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "delims=" %%I in ('dir "D:\Jaye\Programming\Web\Project\scss\*.scss" /A-D /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /R /V "\\_[^\\]*$"') do (
rem Do something with file name assigned to loop variable I.
echo File to process is: "%%I"
)
endlocal
命令 FOR 在后台启动另一个命令过程,其中%ComSpec% /c
和'
中的命令行作为附加参数附加。因此,在Windows安装到C:\Windows
的情况下在后台执行:
C:\Windows\System32\cmd.exe /c dir "D:\Jaye\Programming\Web\Project\scss\*.scss" /A-D /B /S 2>nul | %SystemRoot%\System32\findstr.exe /R /V "\\_[^\\]*$"
命令 DIR 搜索
D:\Jaye\Programming\Web\Project\scss
/S
/A-D
(属性而非目录)导致的文件*.scss
和/B
以裸格式输出找到的文件名,这意味着仅具有文件名和文件扩展名,并且由于选项/S
而具有完整路径。DIR 输出的文件名被重定向到 FINDSTR ,该文件使用正则表达式搜索最后一个反斜杠字符后带有下划线的行,即在文件名开头并输出取反的结果,即文件名不是以下划线开头的所有行。
DIR 输出的错误消息,用于在没有找到符合搜索条件的文件时处理 STDERR ,该错误消息通过使用2>nul
重定向到设备来抑制NUL 。
阅读有关Using command redirection operators的Microsoft文档,以获取2>nul
和|
的解释。重定向操作符>
和|
必须用 FOR 命令行上的脱字符号^
进行转义,以便在Windows命令解释器处理此命令行时将其解释为原义字符。在执行命令 FOR 之前,该命令将在后台启动的单独命令进程中执行嵌入式命令行。
带有选项/F
的命令 FOR 捕获为处理已启动的后台命令过程的 STDOUT 而编写的输出,并在启动{{ 1}}终止。
空行总是被 FOR 忽略,此处不会出现。默认情况下,所有其他行均使用常规空格和水平制表符作为分隔符,分成子字符串。这里不需要这种行拆分行为,因为可能有cmd.exe
个文件名中带有空格的文件。因此,选项*.scss
用于定义一个空的定界符列表,以禁止行分割行为。
delims=
的 FOR 还将忽略行拆分后的第一个子字符串以分号开头的行,因为/F
是默认的行尾字符。文件名可以以分号开头。但是在这种情况下, DIR 输出的文件名总是带有完整路径,因此,任何完整的合格文件名都不可能以分号开头。因此,在这种情况下,可以保留默认的;
。
此解决方案的优势在于,通常包含一个或多个eol=;
的{{1}}文件也可以正确处理,因为这里不需要延迟环境变量扩展。 FINDSTR 进行文件名过滤。
要了解所使用的命令及其工作方式,请打开command prompt窗口,在其中执行以下命令,并非常仔细地阅读每个命令显示的所有帮助页面。
*.scss
!
dir /?
echo /?
endlocal /?
findstr /?
for /?
答案 1 :(得分:1)
通过仅对语句的一侧加双引号,就不会比较同一件事:
示例:
if apples == "apples"
将它们放在彼此下面:
apples
"apples"
这两个永远都不匹配。您几乎可以认为语句的一侧有2个其他字符。
因此,通过在==
两侧引用两个值,您将获得适当的匹配,您只需要:
if "!firstChar!" == "_"
另外,您不需要创建firstchar
变量,虽然可以只保存一行代码,但是您可以只使用以下内容:
if "!name:~0,1!" == "_"
到目前为止,您还没有else
语句,因此也不需要if括号块。因此您的代码可能是:
@echo off & setlocal EnableDelayedExpansion
FOR /R "D:\Jaye\Programming\Web\Project\scss" %%G IN (*.scss) DO (
SET name=%%~nG
echo !name!
echo !name:~0,1!
if "!name:~0,1!" == "_" echo "Dont process this file: %%~nG"
)
最后,您可以执行完全相同的操作,只需通过包含_
排除以findstr
开头的文件即可,因此不需要if
语句,也不需要{{1 }}:
delayedexpansion