Using this batch file I want zip some *.txt files. Each *.txt file in its own zip file. Unfortunately it is not working and i get as output
ECHO is disabled (OFF).
several times. Here is the sourcecode:
#echo off
setlocal EnableDelayedExpansion
for %%i in (*.txt) do (
set filename = %%i
set filenametrunc = %filename:~0,10%
7z a -tzip -mx0 %zipname%
echo %filename% zipped.
)
I read something about EnableDelayedExpansion and activated it. Can't get it working though.
Any help appreciated.
You need to use SetLocal EnableDelayedExpansion and wrap variables in !. Also, don't put spaces between variable names, equals and the value.
set filename = ... makes a variable named %filename % with a value ...
set filename=..... makes a variable named %filename% with a value .....
#echo off
setlocal EnableDelayedExpansion
for %%i in (*.txt) do (
set filename=%%i
set filenametrunc=!filename:~0,10!
7z a -tzip -mx0 !zipname!
echo !filename! zipped.
)
Variables in % inside brackets are evaluated all at the same time, which is before the entire loop starts executing. Your previous code would expand all variables before the set statement ran.
You need to initialize the variable zipname and expand the var using the ! character instead of the % character.
Read HELP SET, specifically
Delayed environment variable expansion allows you to use a different
character (the exclamation mark) to expand environment variables at
execution time.
and change your code to
#echo off
setlocal EnableDelayedExpansion
for %%i in (*.txt) do (
set zipname=%%i
7z a -tzip -mx0 !zipname!
echo !zipname! zipped.
)
Delayed expansion is only needed within the loop if you need to access a variable that you assign inside the loop. But there is no need in your case.
You need to 1st get the correct 7z syntax. Your original code was attempting to put all of the the files in the current directory into a single zip file because you didn't specify a filename. Also your ZIPNAME was uninitialized. You want something like the following.
7z a -tzip zipname filename
I presume you want the name of the zip to be the same as the original filename, except with a .zip prefix instead of .txt. Then all you need is the ~n modifier that gives the base name without the prefix. 7-Zip will automatically append the .zip extension.
for %%i in (*.txt) do 7z a -tzip %%~ni %%i
If you want you can add the -mx0 option, which does no compression. I can't imagine why you would do that for a text file.
for %%i in (*.txt) do 7z a -mx0 -tzip %%~ni %%i
If you want to add your own message
for %%i in (*.txt) do (
7z a -mx0 -tzip %%~ni %%i
echo %%i zipped into %%~ni.zip
)
Related
I"m trying to delete these files with numbers appended to them using a for loop in a Windows batch file.
My problem is that I can't seem to build the filename strings using the for loop, despite several attempts at doing this.
Below is the snippet of my code that I"m trying to run with. As you can see, I've got 4 files named file0.txt, file1.txt, file2.txt and file3.txt in some nested folder, and I'm trying to delete them using a for loop
Ideally I want to be able to be able to set the limit of the for loop depending on how many files there are. And then I'd want to change the file extension from .txt to whatever to delete other files except the ones I want to keep.
Any help would be appreciated!! Here's the code:
setlocal enabledelayedexpansion
set num=3
set /a forLoopLimit=%num%-1
cd folder
FOR /L %%x IN (0,1,%forLoopLimit%) DO (
setlocal enabledelayedexpansion
echo %x
set y=%x
set filename=file%y%.txt
del %filename% /f /q
echo %filename%
)
cd ..
setlocal enabledelayedexpansion
set num=3
set /a forLoopLimit=%num%-1
cd folder
FOR /L %%x IN (0,1,%forLoopLimit%) DO (
echo %%x
set filename=file%y%.txt
ECHO del file%%x /f /q
echo file%%x
)
cd ..
Problems:
To refer to the metavariable (Loop-control variable) x, you need %%x, not %x within a batch file.
setlocal is not a switch. Each time it is used, it establishes a new frame which is terminated by endlocal or reaching end-of-file.
If you are using delayededexpansion then you need to refer to the variable you are changing using !var!, not %var%. !var! means the changed value, %var% means the value of the variable as it was when the for keyword was encountered.
You don't need to use y in your application. %%x is actually a string, but it will be a numeric string, so it can be used in calculations.
The del command is simply echoed above to allow the command to be displayed - in case there's a code error which might delete unexpectedly.
Basically, you fell into the delayed expansion trap (you enabled delayed expansion, but you didn't use it).
But your task can be done without those variables that need delayed expansion. You can use %%x directly and define the rest outside the loop:
#echo off
set num=3
set /a forLoopLimit=%num%-1
set "filebase=file"
pushd folder
FOR /L %%x IN (0,1,%forLoopLimit%) DO (
ECHO del "%filebase%%%x.txt" /f /q
)
popd
Like Magoo, I disarmed the del command by just echoing it. If the output is what you expect, just remove the ECHO.
Using a batch file I'm trying to generate a list of only folders within a location that contain a certain file type, let's call it *.abc
at the moment I only know how to echo a DIR command output to a file called folder.lst, I would like to expand on that and try to either
a) echo only folders containing the *.abc file type to folder.lst
b) remove references in folder.lst of folders that do not contain the *.abc file type.
I also tried having a FOR loop check each line to see if a *.abc file existed in that location and skip it, if not, but I just could not get that to work, here is an example of what I had.
setlocal enableextensions enabledelayedexpansion
FOR /F "delims=" %%C in (folder.lst) do (
set temp=%%C
if not exist !temp!\*.abc (goto skip) else (goto resume)
:resume
then my actions live here
:skip
)
but I am aware I am doing something wrong here...I just do not know what.
Maybe the /R form of the for command will help:
for /r "basedir" %%a in (.) do if exist "%%~a\*.abc" (
echo %%a contains .abc file(s)
)
The %%a will be the directories you want (with a trailing \., but you should be able to not care or accommodate this).
There are problems with such of the script as you have posted in that you can'y use labels within a block statement. You've also not provided any examples.
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir"
SET "lastdir="
FOR /r "%sourcedir%" %%a IN (*.abc) DO IF "!lastdir!" neq "%%~dpa" (
SET "lastdir=%%~dpa"
ECHO %%~dpa
echo "!lastdir:~0,-1!"
)
GOTO :EOF
Each directory found will be echoed twice - one with the trailing \ and once without.
You would need to change the setting of sourcedir to suit your circumstances.
#echo off
setlocal enableextensions disabledelayedexpansion
set "root=%cd%"
for %%a in ("%root%") do for /f "delims=: tokens=2" %%b in ('
dir /a-d /s "%root%\*.abc" ^| find "\"
') do echo(%%~da%%~pnxb
This executes a recursive dir command searching for the indicated file type under the starting point (change root variable to suit your needs). For each found folder we retrieve the folder from the dir header that precedes the file list (the lines that contain a backslash).
To separate the path from the rest of the information in the line, the colon is used as delimiter. As this will leave the drive out of the retrieved information, an aditional for is used to retrieve the drive from the folder reference.
From the command line:
for /f "delims=" %a in ('dir /s /b *.abc') do echo %~dpa >> folders.lst
In a batch file:
for /f "delims=" %%a in ('dir /s /b *.abc') do echo %%~dpa >> folders.lst
The above commands will place only the folder names containing the *.abc files in folders.lst.
Notes:
% should be replaced by %% when the command is used in a batch file.
The ~dp part of %~dpa expands %a to a drive letter and path only. Remove the d if you don't want the drive letter. The p path includes a trailing \ which may be interpreted as an escape character by some commands.
The above commands start the search in the current directory. To search from the root of the current drive you can do cd \ first.
For more information see FOR /F Loop command: against the results of another command and Parameters.
I have about 1000 images and they have name like "IMG-12223". I want to rename them to 1 2 3 4 ... 1000. How can I do that. I have written a batch script which list the files but I don't know how to rename each file. e.g. rename first image with name "IMG-12223" to 1 , second image with name "IMG-23441" to 2 and so on ...
for /r %%i in (*) do (
echo %c%
)
Here's the script. Just put the script in your folder and run it.
#echo off & setlocal EnableDelayedExpansion
set a=1
for /f "delims=" %%i in ('dir /b *') do (
if not "%%~nxi"=="%~nx0" (
ren "%%i" "!a!"
set /a a+=1
)
)
If you want to keep the extensions, i.e. rename "IMG-12223.jpg", "IMG-12224.jpg", etc to "1.jpg", "2.jpg", etc, you may use the following script.
#echo off & setlocal EnableDelayedExpansion
set a=1
for /f "delims=" %%i in ('dir /b *.jpg') do (
ren "%%i" "!a!.jpg"
set /a a+=1
)
[Update] Here're explanations for the lines mentioned in Jack's comment.
setlocal EnableDelayedExpansion
In general, we want the variable a to be delayed expansion when it's executed but not the line is read. Without it, the variable a cannot get its increased value but always 1.
For the detail of EnableDelayedExpansion, please refer to the answer https://stackoverflow.com/a/18464353/2749114.
for /f "delims=" %%i in ('dir /b *.jpg')
Here dir with /b option, lists only file names of all jpg files.
The for loop traverses and renames all jpg files.
For the delims option, since the default delimiter character is a space, without the option delims=, it fails with the image files with spaces in the file names. I.E. for an image file named "img with spaces.jpg", without the option, the value of %%i is "img" but not the whole name "img with spaces.jpg", which is incorrect.
For for loop, please refer to the page http://ss64.com/nt/for_f.html.
if not "%%~ni"=="%~n0"
I have change it to if not "%%~nxi"=="%~nx0" to be more accurate. And the codes attached have been updated.
It's actually used to avoid to rename the bat file itself. If we limit the renaming only upon "jpg" files, then the line is not needed.
%%~nxi is the file name with extension for each file traversed. And %~nx0 is the running bat file with extension. For details, please refer to the page DOS BAT file equivalent to Unix basename command?.
There is no need for a batch script. A simple one liner from the command line can do the job :-)
I use DIR /B to generate the list of files, piped to FINDSTR to number the files, all enclosed withn FOR /F to parse the result and perform the rename.
for /f "delims=: tokens=1*" %A in ('dir /b *.jpg^|findstr /n "^"') do #ren "%B" "%A%~xB"
Double the percents if you want to put the command in a batch script.
Try this, you have pair of namevalues in a text file then loop values and do the magic. Namevalues are separated by empty spaces. This allows you to map old->new filenames accordingly. Or you keep idx+1 counter and use it for new filenames.
keyvalue.bat
#echo off
set idx=0
for /F "tokens=1,2" %%A in (keyvalue.txt) do call :PROCESS "%%A" "%%B"
GOTO :END
:PROCESS
set var1=%~1
set var2=%~2
set /A idx=%idx%+1
echo %var1% goes to %var2% (%idx%)
GOTO :EOF
:END
pause
keyvalue.txt
file888.dat newfile1.dat
file333.dat newfile2.dat
file9.dat newfile3.dat
file01.dat newfile4.dat
I'm trying to find a way to copy two *.log files into one file. My intent was to use For /R to set each filename to a variable. Not as easy as I thought. The log files will have different random names each week that I want to combine into one file called Kip.log.
I only got as far as:
FOR /R D:\Temp %F in (*.log) do echo %~nxF
I don't know how to get further.
Assuming the two log files are in d:\temp then this will suffice.
#echo off
pushd "d:\temp"
copy *.log kip.txt
ren kip.txt kip.log
If you can specify just the files you want using wildcards then this will work
copy *.log kip.log
or
copy a*.log+b*.log kip.log
Type copy /? for Help
To set the variables (and then append) do this:
pushd D:\Test
dir /b *.log >> files.tmp
setlocal enabledelayedexpansion
set count=0
for /f %%a in (files.tmp) do (
set /a count+=1
set "file!1!=%%~a"
)
:: Now you have 2 variables (or more) all file[number]
:: Below is to append
copy "%file1%"+"%file2%" Kip.log
Hope that helped.
#ECHO OFF
SETLOCAL
(
FOR /r D:\temp %%F IN (
zd*.*
) DO TYPE "%%~fF"&echo========%%~fF============
)>KIP.LOG
GOTO :EOF
You don't say why you need to set two variables; for the concatenation task, it's not necessary.
the &echo========%%~fF============ above simply adds a separator with the filename found. It's not required and can be omitted if you wish.
If you "need" the filenames in variables simply to delete them, then
del /s d:\temp*.log
would make short work of that task.
I am using Windows XP and need to create a batch file to move tok.filename to filename.tok.
This works for one file if I type in fix.bat tok.filename.
set filename=%1
set newname=%filename:~4,45%
ren %1 %newname%.tok
I need to type in fix.bat tok*, but this puts tok* in the filename.
How do I get it to read all the files into the filename one at a time?
Use a for statement.
setlocal enabledelayedexpansion
for %%i in (tok.*) do (
set filename=%%i
set newname=!filename:~4,45!
ren %%i !newname!.tok
)
Enabling the delayed expansion makes it so that the variables are evaluated at the time they are used.
Alternatively, since you already have a batch file that works, you could write another batch file that uses the for statement, which calls your working batch file -- like this:
for %%i in (tok.*) do call fix.bat %%i
Or you could run it directly from the command line like this:
for %i in (tok.*) do call fix.bat %i
No need for a batch script
for %F in (tok.*) do for /f "delims=." %X in ("%~xF") do ren "%F" "%X.%~nF"
Double up the percents if used within a batch script.
The above may not give the desired result if more than one . appears in a file name.
For example tok.part1.part2 would become part2.tok.part1.
If you want part1.part2.tok instead, then you can use the following simple script.
#echo off
ren tok.* .*?.tok
for %%F in (.*.tok) do for /f "tokens=* delims=." %%A in ("%%F") do ren "%%F" "%%A"
For an explanation of how that 1st REN works in the 2nd script, see How does the Windows RENAME command interpret wildcards?
I suppose an esoteric argument could be made that a name like tok..name would become name.tok when it should be .name.tok. That could be fixed by using:
#echo off
setlocal disableDelayedExpansion
ren tok.* .*?.tok
for %%F in (.*.tok) do (
set "name=%%F"
setlocal enableDelayedExpansion
ren "!name!" "!name:~1!"
endlocal
)
The nice thing about the solutions above is they don't rely on the length of "tok". A string value of any length could be substituted for "tok" and the code works just as well.
The James L solution works well for a constant length. That solution can be improved a bit.
The 2nd argument to the substring operation is not needed. Removing it lets the solution work no matter how long the full original name is.
The code will fail if a name has an ! in it. Fixed by toggling delayed expansion on and off.
The filenames should be quoted in the REN statement in case of spaces or special characters
.
#echo off
setlocal disableDelayedExpansion
for %%i in (tok.*) do (
set "filename=%%i"
setlocal enableDelayedExpansion
ren "!filename!" "!filename:~4!.tok"
endlocal
)
you can also do the same without delayed expansion (which is slow).
Also, if there is only one dot, without explicitly using lengths of name parts.
%~n expands to filename without extension, and %~x to dot with extension (so I remove dot with :~1).
Also, using %* in for, you may pass arbitrary number of arguments.
And even more. If you add /R bewteen for and %%I (you'll get for /R %%I), it will recurse into subdirs also.
Whole batch file:
for %%I IN (%*) do call :Rename "%~I"
exit /b
:Rename
set newname=%~x1
ren %1 "%~dp1%newname:~1%.%~n1"
exit /b