最近又在写 bat 脚本,主要是利用 for 循环遍历目录下的所有文件,然后做一些处理,很不巧,又遇到一些坑,特此记录一下。
遍历文件的 for 循环比较简单,基本结构如下:
for %%i in (*) do (
echo %%i
)
(*)
表示当前目录下的所有文件,不包括目录。从 *
也可以看出这里是支持通配符的,比如只遍历图片的话可以使用 (*.jpg *.png)
,多个匹配规则直接通过空格分隔。关于这里的匹配规则,网上有大把的资料,我就不再多费笔墨了。
接下来我想在 for 循环内部设置一些变量,发现根本不行。这里是第一个坑,bat 是解释执行的,它并不会重复展开同一个变量,我们需要使用 @setlocal enabledelayedexpansion
开启延迟扩展,并且通过 !variable!
来使用变量。举个例子,遍历输出图片文件的不带扩展名的名字:
@echo off
@setlocal enabledelayedexpansion
for %%i in (*.jpg) do (
set name=%%i
set name=!name:~0,-4!
echo !name!
)
只有在 for 循环内部定义的变量才需要使用 !xxx!
来展开,for 循环外定义的变量还是正常通过 %xxx%
来使用。
接下来是第二个坑,我在 for 循环内调用了另一些 bat 脚本,它需要不带扩展名的文件名称做为参数,假设我的脚本叫 a.bat
和 b.bat
。脚本如下:
@echo off
@setlocal enabledelayedexpansion
for %%i in (*.jpg) do (
set name=%%i
set name=!name:~0,-4!
echo !name!
a.bat !name!
b.bat !name!
)
在第一遍循环时, a.bat
能拿到正确的文件名,但是 b.bat
得到的却是 !name!
,也就是说变量并没有展开。即便是只调用 a.bat
,在进入第二遍循环时,变量也不再展开。这个问题不知道有没有人遇到过,反正网上找不到解决方案。
出现这个问题和调用 bat 有关,如果是可执行程序的话,是没有这个问题的。这里我们不能直接通过 a.bat
来调用脚本,而是应该通过 call a.bat
来调用脚本,这样变量就能正确展开了,如下:
@echo off
@setlocal enabledelayedexpansion
for %%i in (*.jpg) do (
set name=%%i
set name=!name:~0,-4!
echo !name!
call a.bat !name!
call b.bat !name!
)
最后是如果命令中带有 %
,我们需要使用 %
来转义,否则 bat 会把 %
当做变量展开语法,比如使用 ffmpeg 抽帧:
ffmpeg -i %src% -f image2 -y %%d.jpg