Search code examples
for-loopcmdbatch-renamevariable-expansion

cmd for loop mass renaming again oneliner


I'm over my head with this - spent too much time searching already - evidently I don't understand the basics of CMD variables etc. - and it always gives me such a headache

why wouldn't this work?

for %a in (*) do ( set tmpx=%a & echo %tmpx% )

the above code outputs the value of %tmpx% in some other scope - and it is always constant

yes, i run setlocal ENABLEDELAYEDEXPANSION

basically i need to do a simple rename of all files in folder from constantstring_somenameXX.tif to somenameXX.tif, where i.e. constantstring=0000000005

i had to use set because other posts rightly suggested that %a in a for loop has a special behaviour, and the substitutions wouldn't work for it as it is.

i would prefer not to use scripts and/or powershell - unless not using them is impossible

thank you


Solution

  • for %a in (*) do ( set tmpx=%a & echo %tmpx% )
    

    The problem with the previous code is delayed expansion. Yes, you enabled it, but you have not used it, and depending on how you enabled it, it will not work

    In cmd, when a line or block of lines (code inside parenthesis) is reached, it is first parsed and then executed. During the parse phase, variable read operations are removed from the command, replaced with the value in the variable before the command starts to execute. So, if you change the value of a variable inside a line/block you can not retrieve the changed value inside the same line/block as there are no variable reads (they were replaced)

    setlocal enabledelayedexpansion allows to replace (where needed) the variable read syntax from %var% to !var!, indicating to the parser that the read operation will be delayed until the execution phase.

    So, in your case, your code should have been something like

    setlocal enabledelayedexpansion & for %a in (*) do ( set "tmpx=%a" & echo !tmpx! )
    

    BUT this will not work (in default configured environments).

    cmd has two execution modes: batch file and command line. In your case, you are using command line (no escaped percent sign in for loop) and in command line mode the setlocal enabledelayedexpansion will not work. It is intended for batch files (see setlocal /?)

    How to make it work from the command line? By default cmd is started with delayed expansion disabled and you can not enable it if not inside a batch file. But you can start cmd with delayed expansion enabled and run your command in this started instance (see cmd /?)

    cmd /v:on /c "for %a in (*) do ( set "tmpx=%a" & echo !tmpx! )"
    

    Anyway, to solve your rename problem, delayed expansion is not needed

    for %a in (*_*.tif) do for /f "tokens=1,* delims=_" %b in ("%~nxa") do echo ren "%a" "%c"
    

    That is, for each tif file with an underscore, take the name and extension of the file (%~nxa) as a string, and using the underscore as a delimiter between tokens, retrieve the first token (the text on the left of the first underscore) in %b and the rest of the text (to the right of the underscore) into %c. Now, just rename the original file name (stored in %a) to the contents of %c (the text on the right of the underscore)

    In this code rename operations are only echoed to console. If the output is correct, remove the echo command.