ren won't use my variable from one lina above - cmd

I've got a strange problem. I want to rename multiple files in a folder.
So far, so easy - in theory. I use this script:
cd C:\Test
for %%i in (*(7*) do (
set name="%%i"
ren "%name%" "%name:~0,-15%.txt"
)
pause
The strange thing is that he seems to not use the variable "name" I declared
one line above the ren command as you can see in what the console prints:
C:\Test>(
set name="ttttt(7xAAdoc) .txt"
ren "" "~0,-15.txt"
)
What am I missing here? I am running Windows 7, if thats important.
Thanks for any help.

Within a block statement (a parenthesised series of statements), the entire block is parsed and then executed. Any %var% within the block will be replaced by that variable's value at the time the block is parsed - before the block is executed - the same thing applies to a FOR ... DO (block).
Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered.
Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion and use !var! in place of %var% to access the changed value of var or 2) to call a subroutine to perform further processing using the changed values.
In your case,
cd C:\Test
setlocal enabledelayedexpansion
for %%i in (*(7*) do (
set "name=%%i"
ren "%name%" "!name:~0,-15!.txt"
)
note the positioning of the quotes in the first set. The set "var=value" syntax ensures that any trailing spaces on the batch line are not included in the value assigned to var. As you had it, name would be assigned a "quoted" value and the ren command (had it worked) would have been `ren ""filename"" ""firstpartoffilename".txt"

Related

Batch File - Read specific line, and save a specific string in that line as a variable

Is there any way to get for /f loop (or anything else) to read a specific line?
Here is the code I have so far, it reads first word of every line.
#echo off
set file=readtest.txt
for /f "tokens=1 delims= " %%A in (%file%) do (echo %%A)
pause
If someone can point me in the right direction, it'd be much appreciated.
Thanks
Additional Information: I want to make a batch file which will rename a TXT file to a string within that TXT file, located at a specific location. I have figured out how to rename files, all I need to learn to do is to retrieve a string (located at a specific location) with in the file which will go into the name of that TXT file.
Since you haven't fully defined what you mean by "a specific location", I'll make some (reasonable, in my opinion) assumptions, though the method I present is equally valid no matter what your definition turns out to be.
You can get arbitrary lines and arbitrary words on that line by using a line counter variable in conjunction with tokens.
Let's assume your text file name can be found as the second argument on the fourth line of the infile.txt file. You can get that with something like:
#setlocal enableextensions enabledelayedexpansion
#echo off
set /a "line = 0"
for /f "tokens=2 delims= " %%a in (infile.txt) do (
set /a "line = line + 1"
if !line!==4 set thing=%%a
)
endlocal & set thing=%thing%
echo %thing%
This actually uses a few "tricks" which warrant further explanation:
the line counter to ensure you only grab what you want from a specific line, though you could change the test !line!==4 into anything you need such as a line beginning with #, the fifth line containing the string xyzzy and so on.
the use of setlocal/endlocal to effectively give you a scope from which variables cannot leak. This is good programming practice even for a language often not normally associated with such things :-)
the use of endlocal & set to bypass that scope so that thing is the only thing that does actually leak (as it should).
the use of delayed expansion and !..! variables to ensure they're correct within the for loop. Without this, the %..% will always be expand to the value they were set to when the for loop started.
Those last two bullet points are actually related. %..% variables are expanded when the command is read rather than when it is executed.
For a for loop, the command is the entire thing from the for to the final ). That means, if you use %line% within the loop, that will be evaluated before the loop starts running, which will result in it always being 0 (the variable itself may change but the expansion of it has already happened). However, !line! will be evaluated each time it is encountered within the loop so will have the correct value.
Similarly, while endlocal would normally clear out all variables created after the setlocal, the command:
endlocal & set thing=%thing%
is a single command in the context of expansion. The %thing% is expanded before endlocal is run, meaning it effectively becomes:
endlocal & set thing=whatever_thing_was_set_to_before_endlocal
That's why the use of setlocal and endlocal & set is a very useful way to limit variables "escaping" from a scope. And, yes, you can chain multiple & set stanzas to allow more variables to escape the scope.

Windows Cmd Loop name and create folders

I'm trying to figure out how to create a certain number of folders in a Windows batch file. I want to ask the user how many folder they want, and then use that collected number to loop the asking for names of those folders and make them. Here is what I have so far:
pushd C:\Users\%username%\Desktop
set /p FolderLoop="How many folders?: "
for /l %%x in (1, 1, %FolderLoop%) do (
set /p folder="Folder: " %%x
md %folder% %%x
)
The problem I keep having is that I can not make the folders with the proper collected names. The closest I have gotten so far is creating the right amount of folders, but with sequential numeric names (1,2,3, etc.) based om the FolderLoop variable.
You need to read any of the hundreds of responses on SO with regard to delayedexpansion.
Within a block statement (a parenthesised series of statements), the entire block is parsed and then executed. Any %var% within the block will be replaced by that variable's value at the time the block is parsed - before the block is executed - the same thing applies to a FOR ... DO (block).
Within a block statement (a parenthesised series of statements), REM statements rather than the broken-label remark form (:: comment) should be used because labels terminate blocks, confusing cmd.
Hence, IF (something) else (somethingelse) will be executed using the values of %variables% at the time the IF is encountered.
Two common ways to overcome this are 1) to use setlocal enabledelayedexpansion and use !var! in place of %var% to access the changed value of var or 2) to call a subroutine to perform further processing using the changed values.
Note therefore the use of CALL ECHO %%var%% which displays the changed value of var. CALL ECHO %%errorlevel%% displays, but sadly then RESETS errorlevel.
You need delayed expansion:
setlocal enabledelayedexpansion
pushd C:\Users\%username%\Desktop
set /p FolderLoop="How many folders?: "
for /l %%x in (1, 1, %FolderLoop%) do (
set /p "folder=Folder: "
md "!folder!"
)
(the %%x after set /p does nothing. I removed it. I also removed it from md, you don't need it - except you want the counter be part of the foldername.)

How to combine number and string in batch file

I am using batch file to display some kind of number such as
00_test.txt 01_test.txt...10_test.txt 11_test.txt
Hence, This is my code. But I cannot show as my expectation
FOR /L %%x IN (1,1,10) DO (
set "extension=.txt"
set "fullname=%x%_test%extension%"
echo.%fullname%
)
The result of above code are _test.txt _test_txt but expected result are
00_test.txt 01_test.txt
Could you help me edit it?
#echo off
setlocal enabledelayedexpansion
set "baseName=_test"
set "extension=.txt"
for /l %%a in (1 1 10) do (
set "n=0%%a"
echo !n:~-2!%baseName%%extension%
)
When a block of code (in your case the for and the code inside parenthesis) is reached by the parser, all variable reads are replaced with the value in the variable before starting to execute the code. So, if a variable is changed inside the block and the value needs to be retrieved inside the same block, it is necessary to use delayed expansion, telling the parser that variables that are referenced as !var! (instead of %var%), should not be replaced at parse time, its value should be accessed at execution time.
So, in this code %baseName% and %extension% are used with usual syntax as its value does not change inside the for code block, but !n! uses delayed expansion. Its value changes inside the block and this value must be accessed inside the same block.
The concatenation of a 0 prefix and the extraction of two characters on the right from the variable ensure the presence of the initial 0 for values 1 to 9
Try %%x instead of %x:
FOR /L %%x IN (1,1,10) DO (
set "extension=.txt"
set "fullname=%%x%_test%extension%"
echo.%fullname%
)

Batch file variable filenames and editing

Fairly new to the game and have spent many hours looking for help and examples. I've had a version of this working, although I want to streamline the process by having a single input file 'computer_listc.txt'. I basically want to read in a series of folders paths (from computer_listc.txt), and use parts of the path to write further cmd expressions.
My problem is that fname and comp_id are not being set properly. I want to make them equal to T (the filename), and then edit them.
fname needs to be the filepath with the first 12 characters removed. While comp_id needs to equal the computername specified in the filepath e.g.
fname = c_modelling\model\slave1
comp_id = VOSTRO460-1
Heres the script. Can you see my error??
for /f "usebackq tokens=*" %%T in ("C:\c_modelling\Model\cal21_cal\Computer_ListC.TXT") do (
set fname = %%T
ren fname "%fname%" "C:\%fname%:~12%"
set comp_id = %%T
%comp_id% = %{comp_id:0:12}
mkdir %%T > NUL 2>&1
echo cd %fname% >\\%%T\beo_insC.cmd
echo beo >>\\%%T\beo_insC.cmd
robocopy c:\c_modelling\model\cal21_cal \\%%T\ /s /e
start cmd.exe /c psexec \\%comp_id% -c c:\c_modelling\model\cal21_cal\beo_insC.cmd
del \\%%T\beo_insC.cmd
)
Computer_ListC.txt contains the following file names: This will eventually have a long list of computer folder paths.
VOSTRO460-1\c_modelling\model\slave1
VOSTRO460-1\c_modelling\model\slave2
I'm creating a *.cmd file for use with 'psexec', as when I direct the process to a local computer, the path defaults to \system32.
Any assistance would be very helpful!!
First issue is that SPACES in string SET statements are significant. The variablename AND the value assigned will both include any spaces, so set fname = %%T will set a variable named "fname ", not "fname" - and its value will contain the leading space before the value of %%T
Next is the perpetual delayed-expansion issue. Within a block (a sequence of parenthesised statements) any %var% will be replaced by its value at PARSE time - before execution of the loop begins.
To access the RUN-TIME value, you need to execute a SETLOCAL ENABLEDELAYEDEXPANSION statement, and while delayedexpansion is invoked, !var! accesses the RUN-time variable value.
Note however that you cannot simply invoke delayedexpansion within a loop with impunity. There is a limit to the number you can have open at any one time, so you need to 'close the bracket' with an ENDLOCAL command (reaching logical End-Of-File is equivalent to an ENDLOCAL) and the downside is that ENDLOCAL restores the environment to its value when the matching SETLOCAL was invoked. For this reason, SETLOCAL ENABLEDELAYEDEXPANSION is normally executed at the start of the batch, usually after the #echo off
Next issue is
ren fname "%fname%" "C:\%fname%:~12%"
The rename command's syntax is ren sourcename newname - exactly two arguments, enclose any argument containing spaces in "rabbit's ears" Further, the destination name is a NAME only - not a path.
Then there's this:
%comp_id% = %{comp_id:0:12}
Assuming you've fixed this to remove the spaces in variablenames and that comp_id has been assigned the value fred and you've realised that you are dealing with the RUN-time value of comp_id then this would now appear as
!comp_id!=%{comp_id:0:12}
which Batch would interpret as
fred=%{comp_id:0:12}
and promptly give up.
What you are probably expecting to do is
set comp_id=!comp_id:~0,12!
that is, set comp_id to the RUN-time value of comp_id, from the first character (0) for 12 characters.

batch script variable unset in for loop has no effect

Below is my script. I am trying to look into folders one level below and pick out only those folders, hence the ~-9 which extracts the last 9 chars from the path. But the set var= does not unset the variable because the output comes back with the same folder name repeated # times. Also batch doesn't allow me to do this extract trick directly on %%i, hence the need for the local variable.
How do I clear this variable so that it takes the new value in the next iteration?
#echo off
for /d %%i in (%1\*) do (
set var=%%i
echo %var:~-9%
set "var="
)
http://judago.webs.com/variablecatches.htm has an explanation for my problem. The magic lines were setlocal enabledelayedexpansion and calling var as echo !var:~-9!. ! vs % ...wow! cmd still amazes me.
You found the source of your problem, as well as the solution - delayed expansion.
But using FOR while delayed expansion is enabled can cause problems if any of the filenames contain the ! character. The expansion of the for variable %%i will be corrupted if the value contains ! and delayed expansion is enabled. This is not a frequent problem, but it happens.
The solution is to toggle delayed expansion on and off within the loop
#echo off
setlocal disableDelayedExpansion
for /d %%i in (%1\*) do (
set var=%%i
setlocal enableDelayedExpansion
echo !var:~-9!
endlocal
)
I'm also wondering what you mean by "I am trying to look into folders one level below and pick out only those folders, hence the ~-9 which extracts the last 9 chars from the path". I suspect your are trying to get the name of the child folder, without the leading path information. If that is so, then using the substring operation is not a good solution because the length of folder names varies.
There is a very simple method to get the name of the folder without the leading path info:
for /d %%i in (%1\*) do echo %%~nxi

Resources