Reputation: 749
@echo off
cd %~dp0
md .\newfolder
for /f "usebackq delims=" %%f in ("list.txt") do (
call set /a add=%%add%%+1
call set addx=0000%%add%%
call set addx=%%addx:~-3%%
call copy "%%f" ".\newfolder\%%addx%%_%%f"
)
pause
I made simple namechange code. I usually use command without 'call' but here it makes error message . why is that? .. and when i use %variable% not %%variable%% , It doesn't work well.. plz tell me why it happens.. and last question.. environment variable's value is stored until exit cmd . I want to know how i can unset that.. thank you..
Upvotes: 0
Views: 151
Reputation: 130919
All code within a parenthesized block is parsed in one pass. Normal variable expansion using percents occurs at parse time. So if you set a variable within a block, you cannot access the value using normal expansion because the value will be the value that existed before you entered the block.
You have the above situation. There are two classic ways to resolve the problem.
1) You can use CALL and double the percents as you have done. The CALL solves the problem because normal expansion occurs twice for a called line - once for the entire block, and again before the line is executed, but after previous lines in the block have executed. The first expansion converts the double percents to single percents, and the second expansion actually expands the variable.
I do not like this solution because it is slow, and also because the CALL causes problems with quoted ^
characters - they are doubled.
You can use multiple CALLs on the same command. Each Call requires the percents to be doubled. So one CALL requires 2 percents, two CALLs requires 4 perecents, three CALLs 8 percents, etc.
2) I think the preferred solution is to use delayed expansion. It is much faster, and also you never have to worry about escaping or quoting special characters like &
, |
, >
, <
etc. when you used delayed expansion. Delayed expansion does just what it says - the variable is not expanded until just before the line is executed. Delayed expansion must be enabled before it can be used. Within a batch file you can use setlocal enableDelayedExpansion
.
The one problem that can occur with delayed expansion is FOR variables are corrupted if they contain !
and delayed expansion is enabled when they are expanded. That can usually be solved by toggling delayed expansion on and off within the loop.
If you type HELP SET
from the command prompt, you will get a pretty good description of the problem with expanding variables within a block of code, and how delayed expansion can help. The description starts about half way down with the words Finally, support for delayed environment variable expansion...
.
Note - you do not need to expand variables when used within a SET /A computation. SET /A will automatically expand the value at execution time. Undefined variables are treated as zero.
In your code, you can simply use set /a add=add+1
But there is an even simpler shorthand way - you can use the +=
operator: set /a add+=1
.
Here is another way your code could be written without using CALL. The code is untested, but I think I got it right.
@echo off
setlocal disableDelayedExpansion
cd "%~dp0"
md newfolder
set add=0
for /f "usebackq eol=: delims=" %%F in ("list.txt") do (
set /a add+=1
set "file=%%F"
setlocal enableDelayedExpansion
set "addx=00!add!"
copy "!file!" "newfolder\!addx:~-3!_!file!"
endlocal
)
pause
I explicitly initialize add
to 0 because it might already be set to a value. If you know that it is undefined or already set to 0, then the initialization is not needed.
Your FOR loop is dealing with file names, and !
is valid within file names. That is the reason I toggle delayed expansion on and off within the loop - I don't want file names with !
to be corrupted when I expand %%F
. File names can also start with ;
(though highly unlikely). If it does, then FOR will skip that file because the default EOL character is ;
. A file can never start with :
, so I like to set EOL to :
instead.
I put SETLOCAL near the top so that the environment variable definitions do not persist after the batch file completes.
Upvotes: 1