批量FOR循环失败

时间:2015-02-16 22:20:10

标签: batch-file for-loop imagemagick-convert

我一直在搜索SO和谷歌搜索结果差不多一个星期,试图让一个简单的批处理脚本工作。我认为我的问题源于缺乏对批量FOR循环和DelayedExpansion的理解。

在这个主题上有大量相关的问题和答案,但我所看到的帖子中没有一个能够以对我有意义的方式分解信息

setlocal enabledelayedexpansion

SET /a QUALITY=20
SET /a STEP=5
:loop    
convert input.jpg -resize 1080x1080 -quality %quality% -strip ./1080/output.jpg
SET /a quality+=step
for %%G in (./1080/output.jpg) DO (
    set filesize=%%~zG
    if !filesize! LSS 100000 if !quality! LSS 100 goto loop
)

此代码的目的是转换(ImageMagick)初始压缩质量为20的图像,检查文件大小,并在每次迭代时重新开始稍高质量的设置文件大小小于100KB且质量小于100。

实际上,输出是这样的:

>SET /a QUALITY=20
>SET /a STEP=5
>convert input.jpg -resize 1080x1080 -quality 20 -strip ./1080/output.jpg
>SET /a quality+=step
>for %G in (./1080/output.jpg) DO (
>set filesize=%~zG
>if !filesize! LSS 100000 if !quality! LSS 100 goto loop
>(
>set filesize=
>if !filesize! LSS 100000 if !quality! LSS 100 goto loop
>)
>convert export.jpg -resize 1080x1080 -quality 25 -strip ./1080/output.jpg

......等(无限循环)。这一直循环直到被杀死。

此特定测试运行中的output.jpg(质量为20)的文件大小为82.3KB,小于100KB的阈值,因此应该转到循环'并生成一个output.jpg(质量为25),文件大小为96.4KB,转到循环',并生成最终的output.jpg(质量为30),文件大小为109KB。

我相信所需的输出应该是这样的:

>SET /a QUALITY=20
>SET /a STEP=5
>convert input.jpg -resize 1080x1080 -quality 20 -strip ./1080/output.jpg
>SET /a quality+=step
>SET filesize=82300
>if 82300 LSS 100000 if 20 LSS 100 goto loop
>convert input.jpg -resize 1080x1080 -quality 25 -strip ./1080/output.jpg
>SET /a quality+=step
>SET filesize=96400
>if 96400 LSS 100000 if 25 LSS 100 goto loop
>convert input.jpg -resize 1080x1080 -quality 30 strip ./1080/output.jpb
>SET /a quality+=step
>SET filesize=109000
>if 109000 LSS 100000 if 30 LSS 100 goto loop
>

编辑:我尝试过实施David Ruhmann和Mike Nakis的建议,以及来自this post here的OR技巧。不幸的是,结果代码似乎与以前有相同的问题,我留下了无限循环(每次都增加质量)。

SET /a QUALITY=30
SET /a STEP=5
md large
:loop
convert export.jpg -resize 1080x1080 -quality %quality% -strip ./large/xhdpi.jpg
@set res=true
@echo Quality = %quality%
@SET /a quality+=step
@for %%G in (./large/xhdpi*) DO (if %%~zG GTR 100000 set res=false)
@for %%G in (./large/xhdpi*) DO (if !quality! GTR 100 set res=false)
@if "%res%"=="false" exit /b
@if "%res%"=="true" goto loop

在我的代码中,似乎错误的真正问题是%% ~zG没有被赋值。 为什么%% G会返回一个空字符串?

3 个答案:

答案 0 :(得分:1)

:loop    
convert input.jpg -resize 1080x1080 -quality %quality% -strip ./1080/output.jpg
SET /a quality+=step
for %%G in (./1080/output.jpg) DO set filesize=%%~zG
if !filesize! LSS 100000 if !quality! LSS 100 goto loop

免责声明:我无法对此进行测试,因此我很可能犯了一个错误,(我之前从未见过LSS),但是这应该会让你知道你做了什么错了以及如何解决它。

答案 1 :(得分:1)

我通过type 12K文件 qotn.txt 模拟您的例程,使用此例程追加到“.jpg”:

@ECHO Off
setlocal enabledelayedexpansion
SET "filename=u:/sourcedir/1080-output.jpg"
TYPE qotn.txt >"%filename%"
SET /a QUALITY=20
SET /a STEP=5
:loop    
TYPE qotn.txt >>"%filename%"
:: convert input.jpg -resize 1080x1080 -quality %quality% -strip ./1080/output.jpg
SET /a quality+=step
for %%G in (%filename%) DO (
    set filesize=%%~zG
    if !filesize! LSS 100000 if !quality! LSS 100 goto loop
)
DIR/d u:\sourcedir
SET q

GOTO :EOF

......而且效果很好。

所以我所能贡献的只是一些评论 - 是的,不是严格意义上的“回答”,但不容易按摩到“通知”...... soz。

目录分隔符为\而不是/,用于交换机。它似乎有效,但根据我的喜好,我会使用\。请注意,最后,我使用了目标目录的DIR - 因为dir不喜欢%filename%(包含/

如果文件不存在,for %%G将不会执行set / if。因此,无论/ vs \问题如何,都会找到该文件。

真正的问题是,filesize未设置为目标大小的原因,如运行报告中的行>set filesize=所示。

delayedexpansion似乎没有理由。由于quality循环内的for不会发生变化,因此可以使用%quality%%%~zG可以在!filesize!语句中使用if代替quality

请注意,您在运行convert后正在更改quality,因此实际使用的loop is not the quality use by转换. This won't impact the size problem, but it will limit质量'所见的%%G为95%

所以 - 我怀疑使用中的mmetavariable $$~z在循环中处于不同的情况 - 但运行报告另有说法。我甚至尝试在G和{{1}}之间插入一个空格 - 但这会产生不同的结果,而不是无限循环。

赞成决议......

答案 2 :(得分:1)

@echo off
    setlocal enableextensions disabledelayedexpansion

    set "inputFile=.\input.jpg"
    set "outputFile=.\1080\output.jpg"

    set "done="
    type nul > "%outputFile%"
    for /l %%q in (20 5 100) do if not defined done for %%o in ("%outputFile%") do (
        if %%~zo LSS 100000 (
            convert "%inputFile%" -resize 1080x1080 -quality %%q -strip "%outputFile%"
        ) else set "done=1"
    )

此代码只使用for /l来迭代可用的质量选项,而不是为每次迭代跳回。变量用于确定循环是否应继续转换文件,但可以用goto替换以跳出循环。