Issue with numbering script - batch-file

I'm trying to create one of my first ever DOS script (more used to bash).
I'm trying to create a script that would rename my pics using a sequential number and the year as a prefix. I created this script :
#ECHO OFF
setlocal EnableDelayedExpansion
echo.
SET /P Year=Please enter Year (YYYY) :
SET /P Start=Starting Number :
dir
set /A i=%Start%
for %%f in (*.JPG) do call :renameit "%%f"
goto done
:renameit
echo %1 %i%
set str=%i%
set str=0000!str:.=!
set str=!str:~-4!
ren %1 PICT_%Year%_%str%.JPG
set /A i+=1
:done
Issue is that it sometimes works fine, sometimes goes through one additional look renaming back a file that was already renamed. Here are 2 examples (as you can see, I added a DIR and ECHO in the script above for troubleshooting) :
RUN 1 (CORRECT) :
Directory of C:\TEST
07/01/2013 10:55 <DIR> .
07/01/2013 10:55 <DIR> ..
04/08/2011 14:28 16.823 PICT_2012_0005.JPG
04/08/2011 14:28 16.823 PICT_2012_0006.JPG
04/08/2011 14:28 16.823 PICT_2012_0007.JPG
07/01/2013 10:56 368 script.cmd
4 File(s) 50.837 bytes
2 Dir(s) 30.342.901.760 bytes free
"PICT_2012_0005.JPG" 5
"PICT_2012_0006.JPG" 6
"PICT_2012_0007.JPG" 7
RUN 2 (FAILED) :
Directory of C:\TEST
07/01/2013 10:56 <DIR> .
07/01/2013 10:56 <DIR> ..
04/08/2011 14:28 16.823 PICT_2011_0005.JPG
04/08/2011 14:28 16.823 PICT_2011_0006.JPG
04/08/2011 14:28 16.823 PICT_2011_0007.JPG
07/01/2013 10:56 368 script.cmd
4 File(s) 50.837 bytes
2 Dir(s) 30.342.901.760 bytes free
"PICT_2011_0005.JPG" 5
"PICT_2011_0006.JPG" 6
"PICT_2011_0007.JPG" 7
"PICT_2012_0005.JPG" 8
Any idea what I'm doing wrong ?
Thanks

Expanded Comment into a full answer.
It is a known feature/issue/undefined behavior of the for command. When looping through a directory of files and making modification to those files, the for loop does not keep a static list of files in the folder. Instead it just checks for the next file until nothing is returned from the file system. However, when modifying files in the loop, the file system sees the modification as an additional file and it gets sent again to the for loop. This will cause an unknown number (based upon the race condition of the for loop and file system) of files to be reprocessed.
See this forum for an in depth discussion about it.
http://www.dostips.com/forum/viewtopic.php?f=3&t=4138&sid=463cb91964f497c478afcca79c33384a
You can alternatively use this for statement: for /F "delims=" %%F in ('dir /B *.jpg') do call :renameit "%%~fF"
The dir command will generate a static list of the files in the directory at its run time preventing the recursion of files.

Related

Windows 10 batch unzip multiple files with filename the same as zip directory name

I have about 60 files to unzip as you can see below:
I know the 7zip option, which can unzip all of them, but the problem is, that the file inside doesn't match the zip directory name, which would be highly desirable here.
I found some solutions for the batch file here:
https://superuser.com/questions/371384/extract-all-zips-in-a-directory-incl-subfolders-with-a-bat-file-or-dos-comm
and prepared some batch code for this which looks like this:
#echo off
setlocal
cd /d %~dp0
for %%a in (*.zip) do (
Call :UnZipFile "C:\my\Desktop current\Occ KMZ\bat\Aldebaran" "C:\my\Desktop current\Occ KMZ\bat\Aldebaran"
)
exit /b
but it doesn't work at all. I can neither unzip it nor get files.
The 7zip software has a few options, which potentially could be good
but I don't know how to use the 7Zip command line in order to get the unzipped file with the same name as the zip directory.
What should I do to automatize this section?
Here's something (minimal) that should work. Some parts can be done better (error handling and so on). It unzips each archive into a dir named like the archive but without the (.zip) extension.
script00.bat:
#echo off
setlocal enableextensions enabledelayedexpansion
set EXE_7Z="c:\Install\pc064\7Zip\7Zip\Version\7z.exe"
for %%g in ("%~dp0*.zip") do (
call :unpackFile "%%g"
)
goto :done
:unpackFile
set _ARCH_DIR="%~dp1%~n1"
rmdir /q /s %_ARCH_DIR% 2>nul
%EXE_7Z% x -o%_ARCH_DIR% %1 >nul 2>&1
goto :eof
:done
echo Done.
goto :eof
Output:
[cfati#CFATI-5510-0:e:\Work\Dev\StackOverflow]> sopr.bat
### Set shorter prompt to better fit when pasted in StackOverflow (or other) pages ###
[prompt]> tree /a /f q071380369
Folder PATH listing for volume SSD0-WORK
Volume serial number is 00000068 AE9E:72AC
E:\WORK\DEV\STACKOVERFLOW\Q071380369
file00.zip
file01.zip
script00.bat
No subfolders exist
[prompt]> q071380369\script00.bat
Done.
[prompt]> tree /a /f q071380369
Folder PATH listing for volume SSD0-WORK
Volume serial number is 0000006E AE9E:72AC
E:\WORK\DEV\STACKOVERFLOW\Q071380369
| file00.zip
| file01.zip
| script00.bat
|
+---file00
| kkt.py
|
\---file01
URLs.txt

Merging .pdf files with Pdftk

I have many .pdf files on a folder. Also i have a .bat script that works together with Pdftk program. But when i execute the .bat it isn't working.
Follow my script:
#echo off
setlocal enabledelayedexpansion
FOR %%A IN (%*) DO (set command=!command! %%A)
pdftk.exe %command% cat output "%~dp1binder.pdf"
My .pdf files, .bat script and the pdftk.exe with it libiconv2.dll are all in the same folder.
Can someone help me? I need merge all the .pdf files in the folder.
Thank you!
Guys, this simple command are working fine for me, with only one problem. If don't have the file that is in the command, it won't process.
Look the script:
#echo off
pdftk fbw1.pdf fbw2.pdf fbw3.pdf fbw4.pdf fbw5.pdf fbw6.pdf fbw7.pdf fbw8.pdf fbw9.pdf fbw10.pdf fbw11.pdf fbw12.pdf fbw13.pdf fbw14.pdf fbw15.pdf fbw16.pdf fbw17.pdf fbw18.pdf fbw19.pdf fbw20.pdf fbw21.pdf fbw22.pdf fbw23.pdf fbw24.pdf fbw25.pdf fbw26.pdf fbw27.pdf fbw28.pdf cat output testieee.pdf >nul 2>nul
For example: If i don't have the file fbw1.pdf into the directory, it won't process anything. I need that the program process all the files even are missing one or more...
Someone to help?
Thanks!
Ok, the command pdftk *.pdf cat output combined.pdf worked now, but it doesn't merge the .pdf files in sequence.
Ex.: 1.pdf 2.pdf 3.pdf....is the sequence i want, but the command merge in this way: 1.pdf 3.pdf 2.pdf 7.pdf.... There's a way to recognize the sequence?
Thanks
EDIT New approach.
If you drag'n drop file(s) or a folder to the batch or pass at least one file/folder
the following batch will change to the referenced folder and
processes all pdf files in that folder combining them into binder.pdf
an eventually existing binder.pdf is renamed to binder.bak.pdf
:: Q:\Test\2018\06\06\SO_50728273.cmd
#echo off
setlocal enabledelayedexpansion
if "%~1" neq "" (
Echo %~a1|findstr "d" 2>&1>Nul && Pushd "%~f1" || Pushd "%~dp1"
) else (
Echo No arguments, need a path& pause & goto :Eof
)
Del /f binder.bak.pdf 2>&1>Nul
if exist binder.pdf Ren binder.pdf binder.bak.pdf
pdftk.exe *.pdf cat output binder.pdf
PopD
Without knowing what arguments you pass to the batch diagnosing is impossible.%* is replaced with all arguments you pass, the location of the output is determined by the path of the first argument %~dp1
I ran your batch on my ramdisk a:
Dir before:
> dir A:\
Verzeichnis von A:\
2018-06-06 21:57 65.381 SO_5072812.pdf
2018-06-06 21:56 163 SO_50728273.cmd
2018-06-06 21:55 60.649 SO_50728273.pdf
3 Datei(en), 126.193 Bytes
0 Verzeichnis(se), 1.049.452.544 Bytes frei
And after (I named the batch SO_50728273.cmd):
> SO_50728273.cmd a:\*.pdf
> dir
Verzeichnis von A:\
2018-06-06 21:58 125.756 binder.pdf
2018-06-06 21:57 65.381 SO_5072812.pdf
2018-06-06 21:56 163 SO_50728273.cmd
2018-06-06 21:55 60.649 SO_50728273.pdf
4 Datei(en), 251.949 Bytes
0 Verzeichnis(se), 1.049.260.032 Bytes frei
I have the same problem, and I am here. I think I have a better idea to do it. It may help you or the people will come here in future.
for my case,
ls *.pdf > list
for i in `seq 1 340`;do grep "\-$i\-\-" list >> tmp; done
awk '{printf("%s ", $0)}' tmp > oneline
pdftk `cat oneline` cat output test.pdf
for your case
step 1 put all the file names into a file, like namelist.
ls *.pdf > namelist
step 2 sort the name list, suggest there are 400 files.
for i in `seq 1 400`;do grep $i namelist >> sortedNameList;done
step 3 re-organize the sortedNameList.
awk '{printf("%s ", $0)}' sortedNameList > namesInOneline
step 4 merge all the files into a single pdf file
pdftk `cat namesInOneline` cat output final.pdf

What does this specific .cmd file do?

I need help with this cmd file with the following content:
#echo off
for /f "tokens=1,4 delims= " %%a in ('dir e:\ /t:c^|findstr /i /l "v"') do echo %%a %%b
echo on
pause
I can't figure out what it does.
Can anybody help me?
I know the output, but I don't know why it gives me this output.
Here is the output. I didn't want to post it at first because my Windows is German, sorry:
Datenträger in Laufwerk E: ist Volume
Volumeseriennummer: 1AB8-6911
Verzeichnis von e:\
22.09.2015 09:09 0 282ba90118a5f80716
06.10.2015 09:07 0 32f0961d6cc71b3c51bdc6
06.10.2015 09:07 0 4f1ab9edc5ed58c95f344fd2bc84a6ec
02.02.2016 10:56 <DIR> ada200fdfcff43bdf47cf363ddf8
22.09.2015 09:08 <DIR> Besitzer
06.10.2015 09:07 0 bf5f62260169474da0ec9df993590745
06.10.2015 09:07 0 de9afd1afa67ed193d0adb16010b54
10.10.2016 20:29 <DIR> ImportAfter
01.12.2006 22:37 904.704 msdia80.dll
03.10.2016 15:27 <DIR> myxampp
08.09.2015 16:20 <DIR> Schule
08.09.2015 16:20 <DIR> Spiele
6 Datei(en), 904.704 Bytes
6 Verzeichnis(se), 865.948.643.328 Bytes frei
The .cmd file gives me this output:
Datenträger E:
Volumeseriennummer:
Verzeichnis
6 Bytes
But why?
I explain the batch code command by command in order of execution for the line:
for /f "tokens=1,4 delims= " %%a in ('dir e:\ /t:c^|findstr /i /l "v"') do echo %%a %%b
First executed command is:
dir e:\ /t:c
This command according to help output by running in a command prompt window dir /? outputs the files and directories in root directory of drive E: with displaying the creation date because of /t:c instead of the last modification date as by default.
The files and directories are output on NTFS (New Technology File System) formatted drives sorted alphabetically because NTFS does that sort which could be important here.
On FAT16, FAT32 and exFAT drives the files and directories would be listed unsorted as stored in File Allocation Table (FAT). Therefore the usage of DIR parameter /O:N would be additionally needed to get the list sorted by name for any drive independent on file system.
The output of command DIR written to STDOUT is redirected to STDIN of console application FINDSTR for further processing using the pipe redirection operator |. See the Microsoft documentation about Using command redirection operators for details.
| should be interpreted as redirection operator on execution of
dir e:\ /t:c | findstr /i /l "v"
done by command FOR.
To achieve this it is necessary to escape | by putting ^ left of it. The command interpreter cmd.exe on parsing the command line interprets | now as literal character and not as redirection operator because of ^ before.
If just | would have been used instead of ^| within the FOR command line the Windows command interpreter would exit the execution of the batch file on that line because of a syntax error as the redirection operator | would be invalid in the middle of the FOR command line. The error message would be on German respectively English Windows:
English:   | was unexpected at this time.
German: "|" ist syntaktisch an dieser Stelle nicht verarbeitbar.
Running in a command prompt window findstr /? outputs the help of this standard Windows console application. The usage of /i makes the search case-insensitive. And /l tells FINDSTR to interpret the search string "v" as literal string and not as regular expression. So FINDSTR should output all lines containing either V or v.
For the posted output of DIR this means FINDSTR outputs:
Datenträger in Laufwerk E: ist Volume
Volumeseriennummer: 1AB8-6911
Verzeichnis von e:\
6 Verzeichnis(se), 865.948.643.328 Bytes frei
The output of command DIR filtered already by FINDSTR is next processed line by line by command FOR.
The FOR parameters "tokens=1,4 delims= " as explained in help output by running for /? in a command prompt window result in splitting up each line into several strings using the space character as separator for the strings.
The first string should be assigned to the loop variable a as being specified next on the FOR command line.
The fourth string should be assigned to next loop variable with is b according to ASCII table.
Loop variables are case-sensitive because of this feature to assign multiple strings to multiple loop variables.
All other space delimited strings from the line are of no interest and are ignored for that reason.
This additional line filtering by command FOR results in the output:
Datenträger E:
Volumeseriennummer:
Verzeichnis
6 Bytes
But it is quite clear now that this output is not for what the code was designed for originally.
For that reason let us assume the FOR command line
is written for an English Windows instead of a German Windows
(with Germany selected as country in Windows region settings which determines date/time output format as DD.MM.YYYY HH:MM),
root directory of drive E: contains at least one file or directory containing V or v being of interest for the batch code writer,
the files and directories are output sorted by name (by NTFS) and
output is the creation date instead of last modification date.
So the command dir e:\ /t:c outputs:
Volume in drive E is
Volume Serial Number is 1AB8-6911
Directory of e:\
22.09.2015 09:09 0 282ba90118a5f80716
06.10.2015 09:07 0 32f0961d6cc71b3c51bdc6
06.10.2015 09:07 0 4f1ab9edc5ed58c95f344fd2bc84a6ec
02.02.2016 10:56 <DIR> ada200fdfcff43bdf47cf363ddf8
22.09.2015 09:08 <DIR> Besitzer
06.10.2015 09:07 0 bf5f62260169474da0ec9df993590745
06.10.2015 09:07 0 de9afd1afa67ed193d0adb16010b54
10.10.2016 20:29 <DIR> ImportAfter
01.12.2006 22:37 904.704 msdia80.dll
03.10.2016 15:27 <DIR> myxampp
08.09.2015 16:20 <DIR> Schule
08.09.2015 16:20 <DIR> Spiele
13.11.2016 12:53 <DIR> VeryImportantDirectory
6 File(s) 904.704 bytes
7 Dir(s) 865.948.639.232 bytes frei
This output filtered with findstr /i /l "v" is:
Volume in drive E is
Volume Serial Number is 1AB8-6911
13.11.2016 12:53 <DIR> VeryImportantDirectory
And those three lines are filtered next by command FOR which outputs:
Volume E
Volume is
13.11.2016 VeryImportantDirectory
It can be supposed that the first two lines are not really of interest and the last line is what is really of interest for the original batch code writer.
The batch code is most likely written for getting output:
The creation date and name of all files/directories containing v in any case.

Batch File: How to delete files sort by date if there are subfolders in the folder?

Here is one example:
There are 4 files:
C:\Test\1002.bak -- Created on Oct 2nd,2014
C:\Test\1009.bak -- Created on Oct 9th,2014
C:\Test\subfolder\1001.bak -- Created on Oct 1st,2014
C:\Test\subfolder\1008.bak -- Created on Oct 8th,2014
I want to a batch file to delete older files sorted by date, all files including subfolders.
It should be sorted like:
C:\Test\subfolder\1001.bak
C:\Test\1002.bak
C:\Test\subfolder\1008.bak
C:\Test\1009.bak
But if I run the below command, the result has been separated by subfolder.
For instance, "dir /a-d /od /s > result.txt"
result.txt:
Volume in drive C has no label.
Volume Serial Number is AADB-DB05
Directory of c:\test
2014/10/02 11:40 4,220,416 1002.bak
2014/10/09 07:02 1,453,321,216 1009.bak
2014/10/09 18:44 0 result.txt
3 File(s) 1,457,541,632 bytes
Directory of c:\test\subfolder
2014/10/01 10:51 4,220,416 1001.bak
2014/10/08 07:02 1,418,283,008 1008.bak
2 File(s) 1,422,503,424 bytes
Total Files Listed:
5 File(s) 2,880,045,056 bytes
0 Dir(s) 35,598,852,096 bytes free
"dir /a-d /od /s /b> result.txt"
result.txt:
c:\test\1002.bak
c:\test\1009.bak
c:\test\result.txt
c:\test\subfolder\1001.bak
c:\test\subfolder\1008.bak
Is it possible to sort all files including all subfolders by date and then remove the older files when this folder disk size reach the limitation? thank you for your help.
#echo off
set "targetFolder=%cd%"
for /f "skip=4 tokens=2,*" %%a in ('
robocopy "%targetFolder%" "%targetFolder%" /l /nocopy /is /s /njh /njs /ndl /nc /ns /ts
^| sort /R
') do echo del "%%b"
This code uses robocopy command (native in windows from Vista and later versions, available to download for previous versions) not copy files, but to get a list of the files with a timestamp in yyyy/mm/dd hh:nn:ss format. This list is sorted in descending order (sort /r) and the first (newer) files in the list are skipped (skip=4). For the remaining elements in the list a del command is executed.
del operations are only echoed to console. If the output is correct, remove the echo command

Delete SEP VirusDef by date

I have SEP (Symantec Endpoint Protection) in my network.
i want to delete old virus definition folders that take allot of size.
this is the "VirusDef" Folder content:
Directory of \\10.1.66.101\c\Program Files\Common Files\Symantec Shared\VirusDefs
04/06/2014 09:14 PM <DIR> .
04/06/2014 09:14 PM <DIR> ..
03/24/2014 06:19 AM <DIR> 20140322.002
03/26/2014 08:37 PM <DIR> 20140325.009
03/31/2014 01:05 AM <DIR> 20140329.002
04/03/2014 10:24 AM <DIR> 20140401.023
09/15/2010 02:43 PM <DIR> BinHub
10/24/2013 12:56 AM 500,892 Cat.DB
04/03/2014 10:24 AM 34 definfo.dat
09/15/2010 02:43 PM <DIR> TextHub
01/10/2013 11:37 PM 500,660 umcat_01.db
04/03/2014 01:42 PM 141 usage.dat
4 File(s) 1,001,727 bytes
8 Dir(s) 1,114,185,728 bytes free
I have to remain the last modified folder with number, for this case it's 20140401.023 and the other files and folders.
I want to delete the old folders with the numbers such as:
20140322.002
20140325.009
20140329.002
ofcource, those folders get their name by the date the were created.
please help :)
#echo off
setlocal enableextensions disabledelayedexpansion
set "where=\\10.1.66.101\c\Program Files\Common Files\Symantec Shared\VirusDefs"
for /f "skip=1 delims=" %%a in (
'dir /b /ad /tc /o-d "%where%" ^|findstr /r /c:"^[0-9]*\.[0-9]*$"'
) do echo rmdir /s /q "%where%\%%a"
This uses dir command to enumerate the directories, sorted by creation date descending, filtered by findstr to only return the directories with numbered names and extension, from this list, skip the first one (the newer) and delete the rest of the list.
rmdir is only echoed to console. If the output is right, remove the echo command.

Resources