1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.

for %1 %%i in (*.*) do [...] not working

Discussion in 'Support' started by roytam1, Apr 15, 2010.

  1. roytam1

    roytam1

    Messages:
    43
    In CMD, I can place %1 in for statement so that I can control for loop to recursive or not, for example (sizes.bat):
    Code:
    @echo off
    
    set TOTALSIZE=0
    for %1 %%i in (*.*) do call :add %%~zi
    echo %TOTALSIZE%
    set TOTALSIZE=
    goto :EOF
    
    
    :add
     set /A TOTALSIZE+=%1
    
    but with TCC, it shows usage of for statement no matter %1 is set or not.
  2. samintz

    samintz Scott Mintz

    Messages:
    850
    not working

    I haven't tried this but I suspect due to the complex nature of FOR's
    syntax, something is getting tripped up.

    Change this:
    set TOTALSIZE=0
    for %1 %%i in (*.*) do call :add %%~zi
    echo %TOTALSIZE%

    to this:
    set TOTALSIZE=0
    set foreach=for %1 %%i in (*.*) do call :add %%~zi
    %foreach
    echo %TOTALSIZE

    -Scott

    roytam1 <> wrote on 04/15/2010 06:57:16 AM:


    not.
  3. roytam1

    roytam1

    Messages:
    43
    Re: not working

    It doesn't work.

    BTW the rewrited script won't work in CMD any longer.
    I want to keep CMD compatibility of scripts.
  4. vefatica

    vefatica

    Messages:
    4,796
    not working

    I think the problem is the way TCC parses the command line. AFAIK, you can't
    use a variable before FOR's loop variable. It's the "%1" that's the problem.
    You **can** do that with CMD. Apparently (and again unlike CMD) you also can't
    do this:

    set command=FOR /L
    %command %i in (1,1,2) echo %i

    You can, however, use an alias (forget CMD compatibility):

    IFF "%1" == "/R"
    ALIAS myfor FOR /R
    ELSE
    ALIAS myfor FOR
    ENDIFF
    myfor ...

    And this, though awkward, works:

    v:\> set command=for /l

    v:\> %command %%i in (1,1,2) echo %%i
    1
    2

    On Thu, 15 Apr 2010 12:30:10 -0400, samintz <> wrote:

    |I haven't tried this but I suspect due to the complex nature of FOR's
    |syntax, something is getting tripped up.
    |
    |Change this:
    |set TOTALSIZE=0
    |for %1 %%i in (*.*) do call :add %%~zi
    |echo %TOTALSIZE%
    |
    |to this:
    |set TOTALSIZE=0
    |set foreach=for %1 %%i in (*.*) do call :add %%~zi
    |%foreach
    |echo %TOTALSIZE
    |
    |-Scott
    |
    |roytam1 <> wrote on 04/15/2010 06:57:16 AM:
    |
    |
    |
    |---Quote---
    |> In CMD, I can place %1 in for statement so that I can control for
    |> loop to recursive or not, for example (sizes.bat):
    |>
    |> Code:
    |> ---------
    |> @echo off
    |>
    |> set TOTALSIZE=0
    |> for %1 %%i in (*.*) do call :add %%~zi
    |> echo %TOTALSIZE%
    |> set TOTALSIZE> goto :EOF
    |>
    |>
    |> :add
    |> set /A TOTALSIZE+=%1
    |> ---------
    |> but with TCC, it shows usage of for statement no matter %1 is set or
    |---End Quote---
    |not.
    |
    |
    |
    |
    --
    - Vince
  5. samintz

    samintz Scott Mintz

    Messages:
    850
    Re: not working

    The issue has to do with delayed parsing and FOR's loop variable. When
    TCC is parsing the FOR statement it is interpreting %1 as the loop
    variable. It has no way of knowing you meant to use %i instead. The
    following syntax, while not CMD compatible, does work in TCC. Note both
    the use of backticks and double %'s to enable the functionality you're
    trying for.

    @echo off

    set TOTALSIZE=0
    set foreach=`for %1 %%i in (*.*) do call :add %%@filesize[%%i]`
    echo "%foreach"
    %foreach
    echo %TOTALSIZE
    set TOTALSIZEgoto :EOF


    :add
    set /A TOTALSIZE+=%1

    As an alternative using purely TCC syntax:
    echo %@filesize[*.*]

    or

    echo %@eval[%@execstr[4,dir /s /u2]]

    -Scott


    roytam1 <> wrote on 04/15/2010 12:37:36 PM:


  6. samintz

    samintz Scott Mintz

    Messages:
    850
    Re: not working

    Actually, I left out the recurse option:

    echo %@filesize[*]

    or

    echo %@filesize[/S *]

    -Scott

    samintz <> wrote on 04/15/2010 04:26:10 PM:



  7. roytam1

    roytam1

    Messages:
    43
    Re: not working

    but allowing %1 ~ %9 and %* for use as FOR variable breaks compatibility with CMD.

    and the example is just a minimal test case for reproducing the issue.
    my full script look like this:
    Code:
    @echo off
    setlocal EnableDelayedExpansion
    set REDUSIZE=0
    
    for %1 %%i in (*.jpeg;*.jpg) do call :optjpeg "%%~i"
    echo Done. %REDUSIZE% bytes freed.
    
    rem clean up
    set REDUSIZE=
    set rpath=
    set FSIZE=
    SET SIZEDIFF=
    GOTO :EOF
    
    rem sub optjpeg(filename)
    :optjpeg
    SET SIZEDIFF=0
    call :rpath "%~1"
    jpegtran.exe -optimize "%~1" "%~1.new"
    if errorlevel 1 del "%~1.new" & echo %rpath% ... jpegtran internal error. Skipped.
    ujpg.exe "%~1.new" > nul 2>&1
    call :fsize "%~1.new"
    SET /A SIZEDIFF=%~z1-%FSIZE%
    if %FSIZE% EQU 0 del "%~1.new" & echo %rpath% ... Zero byte output. Skipped.
    if %SIZEDIFF% LSS 0 del "%~1.new" & echo %rpath% ... Output [%FSIZE%] is larger than original [%~z1]. Skipped.
    if %SIZEDIFF% EQU 0 del "%~1.new" & echo %rpath% ... Original and output has same size [%~z1]. Skipped.
    
    if exist "%~1.new" call :overwrite "%~1"
    GOTO :EOF
    
    rem sub overwrite(filename)
    :overwrite
     set /A REDUSIZE+=%SIZEDIFF%
     echo %rpath% ... from %~z1 to %FSIZE% [%SIZEDIFF%].
      touch -r "%~1" "%~1.new"
     move /y "%~1.new" "%~1"
    GOTO :EOF
    
    rem sub rpath(filename) OUT: %rpath%
    :rpath
     SET rpath=%~1
     set rpath=!rpath:%CD%\=!
    GOTO :EOF
    
    rem sub fsize(filename) OUT: %FSIZE%
    :fsize
     IF EXIST %1 (
      SET FSIZE=%~z1
     ) ELSE (
      SET FSIZE=0
     )
    GOTO :EOF
    
    endlocal
    
  8. roytam1

    roytam1

    Messages:
    43
    Re: not working

    but replace %%~zi with %%@filesize[%%i] works.
    TCC kills %%~zi here.
    Code:
    @echo off
    
    set TOTALSIZE=0
    set FORSW=for %1
    %FORSW% %%i in (*.*) do call :add %%@filesize[%%i]
    echo %TOTALSIZE%
    set TOTALSIZE=
    goto :EOF
    
    
    :add
     set /A TOTALSIZE+=%1
  9. samintz

    samintz Scott Mintz

    Messages:
    850
    Re: not working

    I have not tested this script, but this is an equivilent TCC script to
    what you are attempting to do in CMD:

    Code:
    @echo off
    setlocal
    set REDUSIZE=0
    do jpg in %1 *.jpeg;*.jpg
            f:\app_re~1\jpegtran.exe -optimize "%jpg" "%jpg.new"
            iff errorlevel 1 then
                    del "%jpg.new"
                    echo %@filename[%jpg] ... jpegtran internal error. 
    Skipped.
                    iterate
            endiff
            f:\app_re~1\ujpg.exe "%jpg.new" > nul 2>&1
            set fsize=%@filesize[%jpg.new]
            iff %fsize LE 0 then
                    echo %@filename[%jpg] ... Zero byte output. Skipped.
                    iterate
            elseiff %fsize GT %@filesize[%jpg] then
                    echo %@filename[%jpg] ... Output [%fsize] is larger than 
    original [%@filesize[%jpg]]. Skipped.
                    iterate
            elseiff %fsize EQ %@filesize[%jpg] then
                    echo %@filename[%jpg] ... Original and output have same 
    size [%@filesize[%jpg]]. Skipped.
                    iterate
            endiff
            set SIZEDIFF=%@eval[%@filesize[%jpg] - %fsize]
            set /A REDUSIZE+=%SIZEDIFF
            echo %@filename[%jpg] ... from %@filesize[%jpg] to %fsize 
    [%SIZEDIFF].
            touch /r "%jpg" "%jpg.new"
            move /y "%jpg.new" "%jpg"
    enddo
    echo Done. %REDUSIZE bytes freed.
    endlocal
    
    -Scott

    roytam1 <> wrote on 04/15/2010 08:35:45 PM:



    Skipped.

  10. roytam1

    roytam1

    Messages:
    43
    Re: not working

    but your script, I can't supply /r in %1 for recursive iteration, and it won't show relative path.

    and I wonder why people there always rewrite one's script to BTM even if he/she wants CMD compatibility.
  11. Steve Fabian

    Steve Fabian

    Messages:
    3,408
    Re: not working

    | but your script, I can't supply /r in %1 for recursive iteration,
    | and it won't show relative path.

    You need to use /S as the first (and only) parameter of the posted batch
    program so it would iterate through all subdirectories of the starting path.
    What do you mean by "relative path"? If %fullpath is the full pathname
    of a file, and the file is located in a subdirectory of %ref_path, the value
    of the function %@replace[%ref_path,,%fullpath] is the path of the file
    relative to directory %ref_path.

    | and I wonder why people there always rewrite one's script to BTM
    | even if he/she wants CMD compatibility.

    Sometimes it is a lot easier to have separate batch files for CMD.EXE
    and for TCC.EXE. Many of us (including myself) never learned how to use
    CMD.EXE, having "grown up" with the JP Software command processors, we never
    downgraded.
    --
    HTH, Steve
  12. roytam1

    roytam1

    Messages:
    43
    In website, JP Software claims "Upwardly compatible with CMD.EXE with literally thousands of additions".
    But actually it doesn't, and failing in most powerful part in CMD: FOR command:
    - wrongly parsing FOR variable with arguments and SET variables.
    - killing extended FOR variables(%%~{*} variables, see FOR /? in CMD for details) if using SET variable to store FOR command.
    and one offing this topic:
    - improper MBCS support.

    How JP Software claim "compatible with CMD.EXE" with these incompatibilities?

    I'm really not trying to criticizing TCC or JP Software, both Take Command(/LE) and TCC(/LE) are still excellent products. But I feel disappointed for JP Software not responding my questions and shifting off problem to "no in-house wide char developers" but not providing ANSI version again as a workaround. 4NT/TCC switched to Unicode only version, but not taking extra care to ANSI-Unicode/Unicode-ANSI conversion and brings trouble to users.
  13. rconn

    rconn Administrator Staff Member

    Messages:
    6,563
    not working

    Well, no -- IMHO this is *not* an issue. You're apparently upset that FOR
    will recognize something other than a single alphabetic character as a FOR
    variable; most users consider this a feature. If you don't duplicate your
    variable names, it will not be a problem.


    As I said, we do not support DBCS environments. When we *did* (in older
    ANSI versions of 4NT), our Asian sales never amounted to more than 0.1% of
    the total. Given this, it makes no financial sense for us to divert limited
    resources to support imaginary non-paying customers.


    We never claimed 100% compatibility -- an obvious impossibility, given that
    (1) different versions of CMD.EXE are incompatible, and (2) it's impossible
    to add features without introducing some level of incompatibility. Given
    the choice of supporting undocumented CMD.EXE bugs (like the FOR or IF
    termination in batch files) or providing additional features (like the batch
    debugger and ON ERROR), we'll go with the features.

    Rex Conn
    JP Software
  14. roytam1

    roytam1

    Messages:
    43
    Re: not working

    I didn't. But instead, I'm pleased that I can use other than single letter as FOR variable.

    But in other side, FOR it trying to use command line arguments(%1 ~ %9, %*) and variable that should evaluated first (%var%) as FOR variable, but not evaluate things(arguments, %var%) first and then execute the FOR statement. Does it make sense?


    then the internal CHCP is nothing other than a joke.
    PLEASE NOTE the >127 part(for example: ¼ Ê Á ð Æ à æ Ì ñ Ç á È ò â ¶ Ö) in ANSI codepages (CP 437/850/etc.) will use 2 bytes to store when using UTF-8(CP 65001).

    without proper support, even UTF-8 support is broken too.

    As I said in that thread, you just not taking care of wchar_t/char count of MultiByteToWideChar and WideCharToMultiByte(IF you use WinAPI to deal with Unicode-ANSI/ANSI-Unicode conversion), which is trivial to fix.

    for unknown undocumented features/bugs, YES we can live without it.
    but for documented behavior or well known behavior, you should make it work BECAUSE you claim the compatibility with CMD.

    But BTW I don't think Microsoft will change the behavior (both documented and undocumented) in CMD in the future because Microsoft is trying to push their PowerShell to users.
  15. rconn

    rconn Administrator Staff Member

    Messages:
    6,563
    Re: not working

    FOR supports all variable types, *except* as the first variable following
    the FOR, where FOR expects only a FOR variable. This is necessary due to
    the much more complex nature of TCC's FOR than CMD's simplistic FOR. TCC
    also doesn't expand the entire line before it's even recognized as a FOR (as
    does CMD), so you don't need the doubled %%'s to prevent premature
    expansion.

    Rex Conn
    JP Software
  16. rconn

    rconn Administrator Staff Member

    Messages:
    6,563
    Re: not working


    Well, OK, if you're ignoring the vast majority of code pages which are *not*
    DBCS.


    There is no UTF-8 support in Windows. A few Windows apps have some custom
    support for UTF-8, but Windows itself is all UTF-16.

    Rex Conn
    JP Software
  17. samintz

    samintz Scott Mintz

    Messages:
    850
    Re: not working

    DO uses /S for recursing into subdirectories. And there is no real
    benefit to bending over backwards to make sure your script works in CMD
    and TCC. If this is a shared script then either make it TCC/LE compatible
    or get licenses for everyone that uses it.

    Ultimately, if you need CMD to run your script from TCC you can always do
    CMD /C cmdscript.bat

    Relative paths are on the suggestion list (at least I know I've made that
    suggestion in the past). Nonetheless, it is still possible to create
    relative paths easily.

    set slen=%@len[%_CWD]
    do jpg in %1 *.jpg;*.jpeg
    echo jpg = "%jpg"
    echo name = %@filename[%jpg]
    echo rel path = .%@right[-%slen,%@full[%jpg]]
    enddo

    -Scott

    roytam1 <> wrote on 04/16/2010 09:13:53 PM:


  18. roytam1

    roytam1

    Messages:
    43
    Re: not working

    These are real test cases to checking TCC's CMD compatibility.

    By the way, about the full script I posted in this thread, I found that "setlocal EnableDelayedExpansion" cannot be use for temporarily enabling Delayed Variable Expansion function.

    I know that there is an option for enable it permanently (requires restart) but I want to use it temporarily inside setlocal/endlocal scope.

    and the Delayed Variable string substitution (!var:from=[to(can be empty)]!) is not working (even if I enabled it in option and restarted).
  19. roytam1

    roytam1

    Messages:
    43
  20. samintz

    samintz Scott Mintz

    Messages:
    850
    Re: not working

    Again if 100% compatibility is necessary then just use CMD to run the
    script.

    CMD /c script.bat

    -Scott

    roytam1 <> wrote on 04/19/2010 12:57:52 PM:


    compatible

    do

    that

    scope.

  21. rconn

    rconn Administrator Staff Member

    Messages:
    6,563
    Re: not working

    SETLOCAL in TCC *does* support ENABLEDELAYEDEXPANSION (in batch files, not
    from the command line). Can you post an example of what is failing for you?


    Again, can you post an example?

    Rex Conn
    JP Software
  22. rconn

    rconn Administrator Staff Member

    Messages:
    6,563
    not working

    TCC already supports all of those arguments (and DisableDelayedExpansion,
    which CMD does not).

    Note that TCC always supports delayed expansion (and always has), unless
    it's explicitly disabled.

    Rex Conn
    JP Software
  23. roytam1

    roytam1

    Messages:
    43
    Re: not working

    Posted before in this thread:
    http://www.jpsoft.com/forums/showpost.php?p=9449&postcount=7

    the :rpath subroutine doesn't replace.
    When it echo %rpath% it print !rpath:[...]\=! directly, such replacement works in CMD.

    a simplified test case here:
    Code:
    @echo off
    setlocal enabledelayedexpansion
    for /R %%i in (.) do (
     call :rpath %%~i
     echo %rpath%
    )
    endlocal
    GOTO :EOF
    
    rem sub rpath(filename) OUT: %rpath%
    :rpath
     rem debug print %1 here
     echo (rpath: %1)
    
     SET rpath=%~1
     set rpath=!rpath:%CD%\=!
    GOTO :EOF
    CMD result:
    Code:
    F:\app_related\TCCLE>rpath
    (rpath: F:\app_related\TCCLE\.)
    .
    (rpath: F:\app_related\TCCLE\abd\.)
    abd\.
    (rpath: F:\app_related\TCCLE\dfe\.)
    dfe\.
    
    F:\app_related\TCCLE>
    TCC result:
    Code:
    [F:\app_re~1\TCCLE]rpath
    (rpath: F:\app_re~1\TCCLE\.)
    !rpath:F:\app_re~1\TCCLE\=!
    (rpath: F:\app_re~1\TCCLE\abd\.)
    !rpath:F:\app_re~1\TCCLE\abd\=!
    (rpath: F:\app_re~1\TCCLE\dfe\.)
    !rpath:F:\app_re~1\TCCLE\dfe\=!
    
    [F:\app_re~1\TCCLE]
    and another type of delayed expansion fails. example from http://ss64.com/nt/syntax-replace.html :
    Code:
    :: To remove characters from the right hand side of a string is 
    :: a two step process and requires the use of a CALL statement
    :: e.g.
    
       SET _test=The quick brown fox jumps over the lazy dog
    
       :: To delete everything after the string 'brown'  
       :: first delete 'brown' and everything before it
       SET _endbit=%_test:*brown=%
       Echo We dont want: [%_endbit%]
    
       ::Now remove this from the original string
       CALL SET _result=%%_test:%_endbit%=%%
       echo %_result% 
    in CMD:
    We dont want: [ fox jumps over the lazy dog]
    The quick brown

    in TCC:
    We dont want: [ fox jumps over the lazy dog]
    The quick brown fox jumps over the lazy dog: fox jumps over the lazy dog
    always enabling delayed expansion even on %var% might not be good on all scripts.

    Quote from http://blogs.msdn.com/oldnewthing/archive/2006/08/23/714650.aspx :
    That's because the command interpreter expanded the environment variables at the time the line was read (not at the time the line is executed), yielding

    set VAR=after & echo before

    As a result, the old value of VAR is echoed. Some people treat this as a feature, allowing them to "restore" a variable without having to save it anywhere:

    set VAR=newvalue & call helper.cmd & set VAR=%VAR%


    a simple test case using this 'feature':
    Code:
    @echo off
    set varx=abc
    set varx=def& call :gsub & set varx=%varx%
    
    :gsub
     echo (gsub: %varx%)
    in CMD:
    (gsub: def)
    (gsub: abc)

    in TCC:
    (gsub: def)
    (gsub: def)


    Also CMD style escape char fails in delayed variables (hellohtml.bat).
    [ script content and results were pasted in pastebin.ca ( http://pastebin.ca/1868846 ) because forum kills html tags. ]
  24. rconn

    rconn Administrator Staff Member

    Messages:
    6,563
    Re: not working

    4NT / TCC has supported delayed expansion for 15 years, LONG before CMD
    implemented it. Changing it now would break a zillion batch files and
    infuriate all the existing TCC users; it's not going to happen.

    Rex Conn
    JP Software
  25. roytam1

    roytam1

    Messages:
    43
    Re: not working

    That's why I said 'might' here.
    I'll also think TCC implementation is better. I just pointed out the difference between CMD and TCC of that.
  26. roytam1

    roytam1

    Messages:
    43
    Re: not working

    Because it is very minor and easily fixed for both CMD and TCC in script, mention this behavior somewhere in documentation is enough.

    and another minor different, if I use variable to store FOR command, the FOR extended variable will be killed.

    Code:
    [F:\app_related\TCCLE]set FORSW=for
    
    [F:\app_related\TCCLE]%FORSW% %%i in (*.exe) do echo %%i
    tcc.exe
    
    [F:\app_related\TCCLE]%FORSW% %%i in (*.exe) do echo %%~si
    ECHO is OFF
    Just let you know this.
  27. rconn

    rconn Administrator Staff Member

    Messages:
    6,563
    Re: not working

    It's well documented and always has been. TCC always does the expansion at
    execution time; this is considered a feature!


    I can conceive of no possible reason to be doing this ...

    Rex Conn
    JP Software
  28. rconn

    rconn Administrator Staff Member

    Messages:
    6,563
    Re: not working

    Leaving aside the horror of this strangled syntax (which would be a one-line
    statement in TCC), this has nothing to do with delayed expansion (which
    isn't even in use in this example).


    The problem here is that the intermediate expansion is:

    CALL SET _result=%_test: fox jumps over the lazy dog=%

    TCC is breaking on the space following the :, and deciding the variable name
    is _test. CMD requires two %'s to enclose the name, but since TCC only
    requires one, it cannot simply go hunting on the remainder of the line
    looking for another %. (And no, this cannot be changed, even as an option,
    without breaking every TCC alias and batch file in existence.) If there is
    no intermediate whitespace (as in the first "SET _endbit=..." command), then
    TCC will detect the trailing % and interpret the command in the same way as
    CMD.

    Rex Conn
    JP Software
  29. samintz

    samintz Scott Mintz

    Messages:
    850
    Re: not working

    As I keep saying, if 100% compatibility is desired then just run the .BAT
    script using CMD. You can enable PathExt and remove .BAT from the PATHEXT
    environment variable and then add an executable extension to run CMD.

    PATHEXT=.COM;.EXE;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.PY
    set .bat=cmd /c

    Rex - there is an odd behavior I noticed doing this. If I have a file
    named FOO.BAT and I type FOO, then the script is launched with CMD.
    However, if I type FOO.BAT then TCC executes the script. Is this an
    ASSOC/FTYPE issue?

    -Scott

    rconn <> wrote on 04/20/2010 09:36:39 AM:


    one-line

    name

    option,

    is

    then

    as

  30. rconn

    rconn Administrator Staff Member

    Messages:
    6,563
    Re: not working

    This fails in CMD -- what is "SET rpath=%~1" supposed to do? In CMD on my
    system (Server 2008), it removes RPATH from the environment, as %~1 AFAIK
    doesn't have any meaning. So the subsequent "set rpath=!rpath:%CD%\=!" does
    nothing, and "rpath" is empty when it returns to the FOR loop. All I get is
    a lot of "echo is off" messages from the FOR loop.

    Rex Conn
    JP Software

Share This Page