Padding filenames with 0s in batch - batch-file

I'm trying to edit some filenames with padded 0s from the command line. I want T9 to become T009 for example.
I tried:
#echo off
set num=99
set newnum=000%num%
set newnum=%newnum:~-4%
rename "T%num%.bmp" "T%newnum%.bmp"
pause
which did indeed changed file t99.bmp to T0099.bmp as I expected. However, when I try a loop like:
#echo off
FOR /L %%G IN (1,1,100) DO (
set num=%%G
echo %%G
set newnum=0000%num%
set newnum=%newnum:~-4%
echo %newnum%
ren "T%num%.bmp" "T%newnum%.bmp"
)
pause
It tells me that 'ECHO is off' and 'The system cannot find the file specified.' Note, it DOES echo %%G so I have no clue what's going on. I think it has something to do with being inside the loop? But I haven't been able to figure that out by googling.
My overall question is: Is there an obvious mistake in my methodology? and Why does the first chunk of code behave as I expect, but not the second?
I just learned batch like an hour ago and so far it's given me a headache. haha.

Set EnableDelayedExpansion then reference the variables with !var! instead of %var%
Fixed code:
#echo off
setlocal EnableDelayedExpansion
FOR /L %%G IN (1,1,100) DO (
set num=%%G
echo !num!
set newnum=0000!num!
set newnum=!newnum:~-4!
echo !newnum!
ren "T%%G.bmp" "T!newnum!.bmp"
)
pause
endlocal
ECHO IS OFF will appear if the variable you are attempting to echo is empty.
For the file not found part, that simply means that the file you are attempting to process is not found. Make sure the .bat file is in the same folder as the .bmp image's. If not, either move it there or cd your way to the path.
To read more about EnableDelayedExpansion, click here
Also, just to let you know, setting the num variable as you did is unnecessary, set newnum=0000%%G would work fine.

Related

How to delete all words after a specific word in batch file

I have a text file named myfile.txt and it has the following text-
Hi my cry die fly
I want to delete all the words after cry.
Please help
Something like this do:
#echo off
setlocal enabledelayedexpansion
for /f "usebackq delims=" %%i in ("myfile.txt") do (
set "line=%%i"
set "line_excl=!line:*cry=!"
call echo %%line:!line_excl!=%%
)
It sets each line in the file as a value to the a variable called %line%, delayedexpansion is needed however, so we enable it and then use the variable as !line!.
We set a search replace variable to be everything up to cry and then simply set echo the !line! by excluding the remaining part, which is everything after cry.

Batch File - Get filename from directory and save as variable

I am trying to read in a directory and get the filename from that directory.
I then want to save the filename as a variable and echo that filename out.
Here is the code I am using:
for /F %%a in ('dir C:\Users\username\Documents\Training\Pentaho\Outputs\BatchFileOutput\ *.csv') do set FileName=%%a
echo %FileName%
I am getting the following when command prompt runs:
"File not found
Directory"
Does anyone know how to resolve this or where I'm going wrong?
Thanks
Safer way of doing the same:
#echo off
setlocal
set "yourDir=C:\Users\username\Documents\Training\Pentaho\Outputs\BatchFileOutput\"
set "yourExt=*.csv"
pushd %yourDir%
for %%a in (%yourExt%) do echo %%a
popd
endlocal
Sets both: Your directory and the extension you are searching for, Changes the directory to the one previously setted possibly including a /drive change and then runs a loop over all files matching your extension and echo them out. To save only the last one you can use:
...do set fileName=%%a
echo %FileName%
Or to use them all within the loop you can use:
#echo off
Setlocal EnableDelayedExpansion
REM Other things done here
do (
REM Do stuff with %%a here
Set filename=%%a
echo !filename!
echo !filename:~0,6!
echo !filename:a=b!
)
If you just want to echo them, you can just go for echo %%a. If you want to do other things like string-substitution or substrings as described in the comments you need DelayedExpansion as shown above. There are a lot of questions on SO as well.
Note that you can get different "parts" of the path of your file. Have a look on this answer I always have a look on as well. Alternatively check the documentation for the for command typing for /? into the command-line.

Rename Files using wildcard paths

Recently I started working and my first task is to write a batch file that automatically changes filenames to filename_date with the original file-ending.
For that you should be able to write paths into a textfile (e.g. paths.txt) and when you start the program, it should take any line (=path->file) from there and rename it.
I got it to work on my PC quiet well but as I gave it to testing they asked to make the use of wildcards Z:\Path\*.* possible.
My current code looks as follows:
#echo off
setlocal EnableDelayedExpansion
cd %~dp0
For /F "tokens=*" %%m in (paths.txt) do (
set path=%%~dpm
set name=%%~nxm
pushd "!path!"
dir
For /r !path! %%f in (!name!) do (
set path=%%~dpf
set name=%%~nf
set ending=%%~xf
set datsave=%%~nxf
set "name=!name!_"
set "name=!name!!date:~6,4!"
set "name=!name!!date:~3,2!"
set "name=!name!!date:~0,2!"
set "name=!name!!ending!"
copy "!datsave!" "!name!"
del "!datsave!"
cls
popd
)
)
I know that a lot of it is probably easier and more efficient to do, but this is my first batch project and I am quiet happy except for the wildcard problem.
So an example would be:
C:\Some\Path\*.*
This line would be in paths.txt.
With the splitting
set path=%%~dpf
set name=%%~nf
set ending=%%~xf
set datsave=%%~nxf
I get the following:
path: C:\Some\Path
name: C:\Some\Path
ending: -empty-
datsave: C:\Some\Path
because name is set to the Path at the start of the first FOR-Loop. But that seems to be working if I do not use wildcards.
Now the question: Why does this happen and how do I get rid of it? Or do I just use the wrong type of wildcards?
Again: This is my first time I work with batch, so it might be something simple ;)
Ok, I figured out 2 problems and now it works
set name=%%~nxm evaluates the wildcard. Even if name is *.txt it will return bar.txt.
I replaced that by a basename computation instead: set name=!name:*\=! done enough times (not very subtle but hey batch files forces us to do such things) which preserves the wildcard
The other problem is the for /R loop: after pushd, the argument needs to be . or it won't be scanned.
Last minor one: use rename instead of copy plus delete. It preserves file time and is very fast. Copying then deleting a large file can take a long time.
#echo off
set DEPTH=20
setlocal EnableDelayedExpansion
cd %~dp0
For /F %%m in (paths.txt) do (
set pth=%%~dpm
set z=%%m
set name=!z!
rem brutal basename. We cannot break the inner loop or
rem it would break the upper loop too
for /L %%I in (1,1,%DEPTH%) do set name=!name:*\=!
rem but we can check if it is really a basename
set chkname=!name:*\=!
if not !chkname!==!name! ( echo please increase DEPTH value
pause
exit /B)
rem set name=%%~nxm
pushd "!pth!"
For /r . %%f in (!name!) do (
set pth=%%~dpf
set name=%%~nf
set ending=%%~xf
set datsave=%%~nxf
set "name=!name!_!date:~6,4!!date:~3,2!!date:~0,2!!ending!
echo renaming "!datsave!" to "!name!"
rem ren "!datsave!" "!name!"
popd
)
)
paths.txt contains just a line C:\full\path\to\test\*.txt
my test directory contains 2 text files and 1 other file
output:
renaming "bar.txt" to "bar_20160812.txt"
renaming "foo.txt" to "foo_20160812.txt"
(just uncomment the ren line to get the job done)
Weeeeell First of all thanks again to #Jean-François Fabre and #aschipfl for their patience with me :)
After the hint with the second batch file I had to test a few things as not everything worked as fine, but now everything works great!
Code of the Main file:
#echo off
setlocal EnableDelayedExpansion
cd %~dp0
set DEPTH=20
For /F %%m in (paths.txt) do (
pause
set pth=%%~dpm
REM pushd !pth!
REM set origpth=!cd!
REM popd
set z=%%m
set name=!z!
For /L %%i in (1,1,%DEPTH%) do set
name=!name:*\=!
set chkname=!name:*\=!
if not !chkname!==!name! ( echo depth to small
pause
exit /B)
rem set name=%%~nxm
pushd "!pth!"
For /r . %%f in (!name!) do (
pushd %~dp0
call renamefiles.bat %%f REM "!origpth!"
popd
)
)
And the code of the sub-file:
#echo off
REM set pth=%~dp1
REM set origpth=%2
REM set origpth=%origpath:"=%\
REM If !pth!==%origpth% (
set path=%~dp1
set name=%~n1
set ending=%~x1
set datsave=%~nx1
pushd !path!
set "name=!name!_!date:~6,4!!date:~3,2!!date:~0,2!!ending!"
pause
echo renaming "!datsave!" to "!name!"
rem "!datsave!" "!name!"
cls
popd
REM )
EDIT: After testing around a bit I figured, that subfolders are included as well! I put extra code to both codes marked with REM and two extra spaces. Take out those REM's and the programm will not longer include subfolders when renaming :)

Batch file for loop dynamic variables from file without setlocal?

I have a simple ini file... really just a key=value file that I want to use to set as variables for my script.
My ini file:
DATABASE=snoopy
My Batch file code
#echo off
SET DATABASE=woodstock
FOR /f "tokens=1,2 delims==" %%a in ('C:\mycfg.ini') do (
echo a=%%a
echo b=%%b
pause
SET %%a=%%b
ECHO DATABASE=%DATABASE%
)
The echo a and b are correct, it shows
a=DATABASE
b=snoopy
But at the end when I echo %DATABASE% after calling the SET %%a=%%b
It still shows
DATABASE=woodstock
If I use delayed expansion, it works but only locally. I need it to overwrite the global so I don't see why this shouldn't work.
Well, no need to do anything to make it work.
It works.
Your problem is that when the for block (all the lines in parenthesis in your code) are read, variables are replaced with their values, so the line echo %DATABASE% is converted in echo woodstock. BUT the variable hold the correct value, changed inside the for loop. Try to place the echo outside of the for and see what the value is.
Delayed expansion is needed when a variable is changed inside a block and it is necesary to access the changed value inside the same block.
Ok I got it now..
Had to enable delayed expansion at the top of the file rather than just on the subroutine call. Then set the %%a and %%b to delayed variables and set them equal to eachother and that worked. Final code:
#echo off
SetLocal EnableDelayedExpansion
SET DATABASE=woodstock
FOR /f "tokens=1,2 delims==" %%a in ('C:\mycfg.ini') do (
set tmpA=%%a
set tmpB=%%b
SET !tmpA!=!tmpB!
)
ECHO DATABASE=%DATABASE%
And that changes it to "snoopy"
Thanks all!

Reading file names and

I would like to create a batch-file that reads the first 10 file names in a spefic directory, and then sets the paths to 10 different variables. For a simple example, the path would be c:\test and inside there, there would be lots of files named file1.tif, file2.tif, etc. I would like to set the variable filepath1 equal to the path of the 1st file, which would be c:\test\file1.tif, and so on for the first 10 files. Here is the code:
#echo off
cd C:\TEST
setlocal ENABLEDELAYEDEXPANSION
FOR /f "delims=|" %%a IN ('dir /b') DO (
CALL SET /a x = !x! +1
if !x! == 1 (
CALL SET /a filepath!x!="C:\TEST\%%a"
)
)
echo %filepath1%
echo %filepath2%
pause
goto EOF
When I run the program, it seems to perform the FOR loop fine, but for filepath1 it displays just 0 and it does not display anything for filepath2. I belive the problem is in the if !X! == 1 and setting the filepath!x!. If I change anything to do with the !x!, it breaks the loop. What can I do to set the variables correctly and limit the loop to perform action on only 10 files?
I'm not quite sure if I got your question correct, because your orginal code contains some things that wouldn't make sense then (or are at least not necessary) :-)
the "delims=|" option you used is not doing anything in your case
when /a option is used for arithmetic (see help set) and is wrong when used with your set filepath!x!... line.
Anyway, the following should work:
setlocal ENABLEDELAYEDEXPANSION
cd C:\Test
FOR /f %%a IN ('dir /b') DO (
SET /a x = !x! +1
SET filepath!x!="C:\TEST\%%a"
if !x! equ 10 goto done
)
:done
rem filepath1 to filepath10 are defined now, given there were up to 10 matching
rem files in the first place.
echo %filepath1%
echo %filepath2%
pause
The code above does not do any error checking and does not verify that the files in question are actually called file1.tif to file10.tif. From your question (and sample code) it is not quite clear if that is really necessary in your case. You might want to clarify that, so that the above code can be improved regarding it.

Resources