This is more sort of a continuation to this question, I referred to the answer section and its fine but it doesn't seem to work for JSON files. The below is my JSON
{
"id": "ee308826-5aa6-412b-ba65-fd647d9cc8e8",
"name": "Stub",
"request": {
"url": "/World/Wilfred",
"method": "GET"
}
}
I need the file to be renamed with "Stub_GET_World_Wilfred.json" which is of the syntax name_method_url ( without the / )
Script from the Original Question :
#echo off
for %%i in (%1) do (
for /f "tokens=2 delims==" %%j in ('findstr /B /I "Description=" "%%i"') do (
ren "%%i" "%%j.temp_txt"
)
)
ren *.temp_txt *.txt
The following commented batch file could be used for this task:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
set "ErrorCount=0"
set "FileCount=0"
rem Was the batch file called with an argument string to process one file?
if not "%~1" == "" (
rem Is there no file (or directory) with the name passed to the batch file?
if not exist "%~1" (
set "ErrorCount=1"
echo ERROR: File "%~1" does not exist.
) else call :ProcessFile "%~1"
goto EndBatch
)
rem Process all files with the file extension .json in current directory.
for /F "eol=| delims=" %%I in ('dir *.json /A-D /B 2^>nul') do call :ProcessFile "%%I"
goto EndBatch
rem Rund FINDSTR on the file (or wrong on directory) in a background command
rem process started by FOR to find lines with the literal string "url" or the
rem literal string "method" in any case and process this line by splitting it
rem into substrings using comma, colon, horizontal tab and normal space as
rem string delimiters with using first substring without the surrounding quotes
rem as environment variable name and assigning the second substring without the
rem surrounding quotes to the environment variable. Please note that this code
rem does not work for a url with a colon or comma inside.
:ProcessFile
set /A FileCount+=1
set "method="
set "url="
for /F "tokens=1,2 delims=,: " %%J in ('%SystemRoot%\System32\findstr.exe /I /L /C:"\"url\"" /C:"\"method\"" "%~1"') do set "%%~J=%%~K"
if not defined url (
rem There was no string "url" found in the file (or the passed string
rem was a folder name) or the line with "url" has not a string value.
set /A ErrorCount+=1
echo ERROR: Could not find a url in "%~1".
goto :EOF
)
if not defined method (
rem There was no string "method" found in the file (or the passed string
rem was a folder name) or the line with "method" has not a string value.
set /A ErrorCount+=1
echo ERROR: Could not find a method in "%~1".
goto :EOF
)
rem Create the new file name by concatenating Stub_ with the method string
rem and with the url string read from the file with each slash replaced by
rem an underscore in url and file extension .json appended. There is not
rem replaced any percent encoded character in the url by the appropriate
rem character.
set "FileName=Stub_%method%%url:/=_%.json"
rem There is nothing done on name of processed file has case-insensitive
rem compared already the right name.
if /I "%~nx1" == "%FileName%" goto :EOF
rem Next is checked if a file with new name exists already in directory of the
rem file passed to the batch file which makes it impossible to rename the file.
if exist "%~dp1%FileName%" (
set /A ErrorCount+=1
echo ERROR: A file with name "%FileName%" exits already in "%~dp1".
goto :EOF
)
rem Otherwise the file is renamed which can still fail for various reasons.
ren "%~1" "%FileName%"
if errorlevel 1 (
set /A ErrorCount+=1
echo ERROR: File "%~1" could not be renamed to "%FileName%".
goto :EOF
)
echo Renamed file "%~1" to "%FileName%".
goto :EOF
:EndBatch
set "Plural_S_Files="
if not %FileCount% == 1 set "Plural_S_Files=s"
set "Plural_S_Errors="
if not %ErrorCount% == 1 set "Plural_S_Errors=s"
echo/
echo Proccessed %FileCount% file%Plural_S_Files% with %ErrorCount% error%Plural_S_Errors%.
if not %ErrorCount% == 0 echo/& pause
endlocal
ATTENTION: There must be a horizontal tab and a space after delims=,: left to " in the batch file. Please make sure to have only these two characters and not multiple spaces in the batch file after copying and pasting the batch file code.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
dir /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
pause /?
rem /?
ren /?
set /?
setlocal /?
See single line with multiple commands using Windows batch file for an explanation of operator &.
Related
I want to rename all files in directory by adding filesize to it by batch file. e.g apple.bmp of size 66kb changes to apple[66KB].bmp. this is the code i am trying
> SET count=1 SET foldersize=0 FOR /f "tokens=*" %%F IN ('dir /s/b
> %folder%') DO (call :calcAccSize "%%F") echo %filesize% GOTO :eof
>
> :calcAccSize REM echo %count%:%1 REM set /a count+=1 set /a
> foldersize+=%~z1
>
> ren %1 %~nx1[%~z1].mp4 GOTO :eof
>
> #pause
[edit /]
Assumed actual code:
SET count=1
SET foldersize=0
FOR /f "tokens=*" %%F IN ('dir /s/b %folder%') DO (
call :calcAccSize "%%F"
)
echo %filesize%
GOTO :eof
:calcAccSize
REM echo %count%:%1
REM set /a count+=1
set /a foldersize+=%~z1
ren %1 %~nx1[%~z1].mp4
GOTO :eof
#pause
The following batch file renames all files in current directory with appending [xKB] left to file extension, except
the batch file itself on being also in the current directory and
the files containing already [xKB] in their file name.
The code is:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "eol=| delims=" %%I in ('dir /A-D /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /R /V "\[[0123456789][0123456789]*KB\]"') do if not "%%~fI" == "%~f0" (
set /A FileSizeKB=%%~zI / 1024
set "NameFile=%%I"
if not "%%~nI" == "" (
set "FileName=%%~nI"
set "FileExt=%%~xI"
) else (
set "FileName=%%I"
set "FileExt="
)
setlocal EnableDelayedExpansion
ren "!NameFile!" "!FileName![!FileSizeKB!KB]!FileExt!"
endlocal
)
endlocal
The files can contain a space or one of these characters &()[]{}^=;!'+,`~ in their file name. The code renames also files correct starting with a dot and having nor more dot, i.e. a file with name like .Test File!.
The arithmetic expression works only for files with a file size smaller than 2.147.483.648 bytes, i.e. less than 2 GiB because of the Windows command processor cmd.exe supports only arithmetic expressions by using 32-bit signed integers with a value range of −2147483648 to 2147483647 (−231 to 231−1).
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /? ... explains %~f0 ... batch file name with full path.
dir /?
echo /?
endlocal /?
findstr /?
for /?
if /?
ren /?
set /?
setlocal /?
Read the Microsoft documentation about Using command redirection operators for an explanation of 2>nul and |. The redirection operators > and | must be escaped with caret character ^ on FOR command line to be interpreted as literal characters when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with redirecting the output file names list to findstr with using a separate command process started in background using %ComSpec% /c and the command line within ' appended as additional arguments.
#ECHO OFF
if not exist "C:\test\test.txt" (
goto end
) else (
goto loop
)
:loop
echo Insert the name of the folder:
set /p name=<"C:\test\test.txt"
for /F "skip=1 delims=" %%a in ('type "C:\test\test.txt" ^& del "C:\test\test.txt"') do >> "C:\test\test.txt" echo %%a
echo Insert the name of the subfolder:
set /p name2=<"C:\test\test.txt"
for /F "skip=1 delims=" %%a in ('type "C:\test\test.txt" ^& del "C:\test\test.txt"') do >> "C:\test\test.txt" echo %%a
md "C:\test\%name%\testing %name2% 999"
move "C:\test\*%name2%*.txt" "C:\test\%name%\testing %name2% 999"
if exist "C:\test\test.txt" goto loop
:end
pause
exit
I want to make an "if" before the "echo Insert the name of the folder:" part, so that if the 1st line of the "test" text file contains any of this characters "\ / : * ? " < > |" it will delete those special characters
It looks like the file C:\test\test.txt should contain a set of folder names with on odd lines the main folder name and on even lines the subfolder name without path.
Microsoft explains on documentation page about Naming Files, Paths, and Namespaces which characters are not allowed in file/folder names.
If a line in the text file with the folder names contains an invalid character for a folder name, removing the character is not really the solution as it is most likely of no real help to move the files which contain the subfolder name into the subfolder.
I suggest following batch file for this task:
#echo off
if not exist "C:\test\test.txt" goto end
setlocal EnableExtensions DisableDelayedExpansion
set "MainFolderName="
set "SubfolderName="
for /F "usebackq eol=| delims=" %%I in ("C:\test\test.txt") do (
if not defined MainFolderName (
set "MainFolderName=%%~nxI"
) else (
set "SubfolderName=%%~nxI"
setlocal EnableDelayedExpansion
md "C:\test\!MainFolderName!\testing !SubfolderName! 999" 2>nul
if exist "C:\test\!MainFolderName!\testing !SubfolderName! 999\" (
move "C:\test\*!SubfolderName!*.txt" "C:\test\!MainFolderName!\testing !SubfolderName! 999\"
rd "C:\test\!MainFolderName!\testing !SubfolderName! 999\" 2>nul
)
endlocal
set "MainFolderName="
set "SubfolderName="
)
)
endlocal
:end
pause
I do not recommend using command exit in a batch file, especially not at end of the batch file. This is not useful and has just the disadvantage that debugging the batch file becomes a nightmare.
The command FOR with option /F and the other options in double quotes processes the text file line by line with skipping empty lines and lines starting with |.
The first string read from a line after last \ or / is assigned to variable MainFolderName.
The second string read from a line after last \ or / is assigned to variable SubfolderName.
Next delayed expansion is enabled to be able to reference the string values of the two environment variables.
The directory is created with suppressing an error output by redirecting it from handle STDERR to device NUL. An error is output if folder or subfolder name contains an invalid character.
The IF condition checks, if the directory really exists which is not the case on invalid character in one of the two directory names. So the command MOVE is executed only on valid folder names and command RD removes the directory on being still empty after moving the files.
Then the two environment variables are deleted before processing the next two lines from text file.
It would be possible to process the lines read from text file as described for example at:
How to verify if variable contains valid filename in Windows Batch
But I think, this is not really necessary. The best folder name verification is done by the file system itself. So removing all characters from a line read from a text file which are not allowed in a folder name is not really needed in this case.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
echo /?
endlocal /?
for /?
goto /?
if /?
md /?
move /?
pause /?
rd /?
set /?
setlocal /?
Read also the Microsoft article about Using command redirection operators for an explanation of 2>nul.
You can remove special characters with a batch script using regex in vbscript : Demo Here
#echo off
Color 0A
Title How to verify if variable contains valid filename in Windows Batch
echo(
Echo Enter filename for this project
set /p "my_filename="
echo(
echo Before Removing the special char the filename is like this : "%my_filename%"
pause
echo(
Call :Remove_Special_Char "%my_filename%" NewFileName
echo After Removing the special char the filename becomes like this : "%NewFileName%"
pause & exit
::-----------------------------------------------------------------------------------
:Remove_Special_Char <String> <Variable to Set>
(
echo WScript.StdOut.WriteLine Search_Replace(Data^)
echo Function Search_Replace(Data^)
echo Dim strPattern, strReplace, strResult,oRegExp
echo Data = wscript.Arguments(0^)
echo strPattern = "[\\\/:*?\x22<>|]"
echo strReplace = ""
echo Set oRegExp = New RegExp
echo oRegExp.Global = True
echo oRegExp.IgnoreCase = True
echo oRegExp.Pattern = strPattern
echo strResult = oRegExp.Replace(Data,strReplace^)
echo Search_Replace = strResult
echo End Function
)>"%tmp%\%~n0.vbs"
#For /f "delims=" %%i in ('cscript //nologo "%tmp%\%~n0.vbs" "%~1"') do ( Set "%2=%%i" )
If Exist "%tmp%\%~n0.vbs" Del "%tmp%\%~n0.vbs"
Exit /B
::----------------------------------------------------------------------------------
I am new to batch scripting
I am supposed to write a batch file to read a text file and two command line parameter say ,"task" and "choice".There can be two values for choice-"enable" and "disable"
Now i would want to input the file line by line and match the starting of line with "task" command line argument entered followed by a colon(:) followed by anything .
Now if the choice is "enable" then i have to put ":N" in the respective lines in which the task matches if it doesnt contain a :N already
My text file would contain entries like:
24343:abc:dsd:N
233:zxzxzc
2344:cxzc:xzc
and if i run a command like
myscript.bat 2344 enable
the output of the script should be that the file should be
24343:abc:dsd:N
233:zxzxzc
2344:cxzc:xzc:N
I have been trying to write the code for this for two whole days but still havent been successful.
After all the reading,this is what i have written till now
#echo off
set /A taskname= %1
set choice= %2
FOR /F "tokens=* delims=" %%x in (testdoc.txt) do (
echo %x%|findstr /R "^'%1'.*[^:][^N]$"
if errorlevel 1 (echo does not contain) else (echo contains)
)
In this,i was trying to compare line by line with the regex but it doesnt work as intended.
Any help would be appreciated
Thanks
Regular expression replaces are not possible with pure usage of Windows command line interpreter cmd.exe or the console applications installed with Windows. This would require usage of a scripting language/interpreter with support for regular expression replaces in files like PowerShell or JScript which would be most likely better choices for this task.
However, a pure batch file solution is also possible for this task as it can be seen on commented batch code below with lots of extra features.
#echo off
set "TempFile=
rem Is first parameter /? for getting help?
if "%~1" == "/?" goto ShowHelp
rem Is the batch file not started with any none empty parameter?
if not "%~1" == "" (
rem Does the first parameter not consist of only digits 0-9?
for /F "delims=0123456789" %%I in ("%~1") do goto ShowHelp
)
rem Is there also specified a second parameter?
if not "%~2" == "" (
rem Is the second parameter neither enable nor disable (case-insensitive)?
if /I not "%~2" == "disable" if /I not "%~2" == "enable" goto ShowHelp
)
rem Setup a local environment for this batch file.
setlocal EnableExtensions DisableDelayedExpansion
rem Define the name of the text file without or with path to modify.
rem Define the name of the temporary file needed to modify the file.
set "TextFile=TextFile.txt"
set "TempFile=%TEMP%\%~n0.tmp"
rem Does the text file to modify exist at all?
if not exist "%TextFile%" goto MissingFile
rem Was a task number specified on starting this batch file?
if not "%~1" == "" set "TaskNumber=%~1" & goto FindTask
rem Prompt the user for the task number and make sure that the user really
rem enters a number by verifying user input using a very secure method.
:PromptNumber
set "TaskNumber="
set /P "TaskNumber=Enter task number: "
if not defined TaskNumber goto PromptNumber
setlocal EnableDelayedExpansion
for /F "delims=0123456789" %%I in ("!TaskNumber!") do endlocal & goto PromptNumber
endlocal
:FindTask
rem Does the file to modify contain the number at beginning of a
rem line as specified with first parameter and followed by a colon?
%SystemRoot%\System32\findstr.exe /B /L /M /C:"%TaskNumber%:" "%TextFile%" >nul 2>&1
if errorlevel 1 goto MissingNumber
rem Has the user specified the action to perform as second parameter.
if /I "%~2" == "enable" set "TaskAction=1" & goto ModifyFile
if /I "%~2" == "disable" set "TaskAction=2" & goto ModifyFile
rem Prompt the user for the action to perform.
%SystemRoot%\System32\choice.exe /N /M "Press Y to enable or N to disable task: "
set "TaskAction=%ERRORLEVEL%"
rem Copy the file with ignoring empty lines and lines starting with a
rem semicolon to temporary file with modifying all lines starting with
rem the specified task number according to specified action to perform.
rem But delete the temporary file before if existing by chance.
:ModifyFile
del "%TempFile%" 2>nul
set "FileModified="
for /F "usebackq tokens=1* delims=:" %%I in ("%TextFile%") do (
if not "%%I" == "%TaskNumber%" (
echo %%I:%%J>>"%TempFile%"
) else (
set "TextLine=%%I:%%J"
call :ModifyLine
)
)
rem Was no line modified on copying all the lines to temporary file?
if not defined FileModified del "%TempFile%" & goto EndBatch
rem Move the temporary file over the text file to modify.
move /Y "%TempFile%" "%TextFile%" 2>nul
rem Was the text file overwritten by command MOVE?
if not errorlevel 1 goto EndBatch
rem Inform the user that the text file to modify could not be
rem modified because of being read-only or missing appropriate
rem NTFS permissions or a sharing access violation occurred.
del "%TempFile%"
for /F %%I in ("%TextFile%") do set "TextFile=%%~fI"
echo/
echo ERROR: "%TextFile%" could not be modifed.
echo/
echo Please make sure the file has not read-only attribute
echo set, is not opened in any application and you have
echo the necessary permissions to overwrite this file.
goto HaltBatch
rem This is a subroutine which modifies a line with right task
rem number according to action to perform and outputs this line
rem into the temporary file. It records also if the line needed
rem to be modified at all.
:ModifyLine
if %TaskAction% == 1 (
if not "%TextLine:~-2%" == ":N" (
set "TextLine=%TextLine%:N"
set "FileModified=1"
)
) else (
if "%TextLine:~-2%" == ":N" (
set "TextLine=%TextLine:~0,-2%"
set "FileModified=1"
)
)
>>"%TempFile%" echo %TextLine%
goto :EOF
rem Get name of file with full path which works also for not existing
rem file and inform the user about missing file to modify with full
rem path to see also where this batch file expected it on execution.
:MissingFile
for /F %%I in ("%TextFile%") do set "TextFile=%%~fI"
echo/
echo ERROR: "%TextFile%" does not exist.
goto HaltBatch
:MissingNumber
rem The specified number does not exist in the file to modify
rem at beginning of a line. Inform the user about this error.
echo/
echo ERROR: %TaskNumber% not found in file "%TextFile%".
goto HaltBatch
:ShowHelp
echo/
echo Usage: %~nx0 [task] [disable ^| enable]
echo/
echo task ...... number of the task to enable or disable.
echo disable ... disable the specified task.
echo enable .... enable the specified task.
echo/
echo %~nx0 can be also started without any parameter.
echo In this case the task number and the action to perform
echo can be entered during the execution of the batch file.
:HaltBatch
echo/
pause
echo/
:EndBatch
if defined TempFile endlocal
The command line set "TextFile=TextFile.txt" must be modified to your environment.
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
choice /?
del /?
echo /?
endlocal /?
findstr /?
for /?
goto /?
if /?
move /?
pause /?
rem /?
set /?
setlocal /?
Further read following:
DosTips forum topic ECHO. FAILS to give text or blank line - Instead use ECHO/
Microsoft article about Using Command Redirection Operators
Stack Overflow answer on Where does GOTO :EOF return to?
Stack Overflow answer on Single line with multiple commands using Windows batch file
I need to move few files from one folder to sub folder. My folder structure is already ready.
File current folder: D:\AB\*.*
The file name is: SS-AA-Report-Temp File for Script Testing-Daily-31March.txt
Destination folder: D:\AB\Pm 1.1 File For Script\Daily\
How to check file name substring with folder name substring and move?
Note I have multiple files like this.
set Path1= d:\AB
Pushd %Path1%
echo %Path1%
for %%i in (*.*) do SET "FName=%%~ni"
For /F "Tokens=4-5 Delims=-" %%A In ("%FName%") Do (
Set "FoldOne=%%A"
Set "FoldTwo=%%B"
)
echo out %RDate%
mkdir %Path1%\"%FoldOne%"\"%FoldTwo%"\%RDate%
move %Path1%\"%FName%".* %Path1%\"%FoldOne%"\"%FoldTwo%"\%RDate%\
Edit:
File names format:
A-A-Format-Here First connectivity install on Day 0 regurlarly-Daily-All-2017-03-27-09-31-16.xls
A-A-Format-Already First connectivity with 10 days created-Weekly-All-2016-11-28-10-01-02.csv
A-A-Report-withname 1.2 Sample Report (Network Plan Report)-Daily-Detail-2017-01-03-23-53.xls
A-A-Report-Nextreport 1.2 Sample Report (Network Plan Report)-Weekly-Detail-2017-01-03-23-02-53.csv
Now my folder structure is:
D:\AB\Pm 1.1 First connectivity install on Day 0\Daily\05042017
D:\AB\Pm 2.1 First connectivity with 10 days\Weekly\29032017
D:\AB\Pm 1.2 Sample Report\Daily\05042017
D:\AB\Pm 1.2 Sample Report\Weekly\29032017
And here is the batch file I have already:
set Path1= d:\AB
Pushd %Path1%
echo %Path1%
for %%i in (*.*) do SET "FName=%%~ni"
For /F "Tokens=4-5 Delims=-" %%A In ("%FName%") Do (
Set "FoldOne=%%A"
Set "FoldTwo=%%B"
)
echo 1 %FoldOne%
echo 3 %FoldTwo%
IF %FoldTwo% == Daily (
echo here Daily
For /F UseBackQ %%A In (
`PowerShell "(Get-Date).AddDays(-1).ToString('ddMMyyyy')"`
) Do (Set "RDate=%%A"
echo ffor %RDate%
)
)
IF %FoldTwo% == Weekly (
Echo Weekly
For /F UseBackQ %%A In (
`PowerShell "(Get-Date).AddDays(-7).ToString('ddMMyyyy')"`
) Do (Set "RDate=%%A"
echo %RDate%
)
)
mkdir %Path1%\"%FoldOne%"\"%FoldTwo%"\%RDate%
move %Path1%\"%FName%".* %Path1%\"%FoldOne%"\"%FoldTwo%"\%RDate%\
Pushd d:\
GoTo :EOF
The logic for matching file name substrings with folder name is still very fuzzy.
However, I coded two possible solutions doing both the same using partly different methods.
The first complete batch code:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
cd /D "D:\AB"
rem Get name of each subfolder starting with string Pm, a space, two single
rem digit numbers separated by a dot, one more space and more characters to
rem indexed environment variables for later usage. And assign the substring
rem after the first 7 characters of each folder name also to an index
rem environment variable.
set FolderIndex=0
for /D %%I in ("Pm ?.? *") do (
set "FolderName!FolderIndex!=%%I"
set "CurrentPath=%%I
set "FolderPart!FolderIndex!=!CurrentPath:~7!"
set /A FolderIndex+=1
)
set "FolderCount=%FolderIndex%"
rem set Folder
rem Get date of yesterday and date of a week ago.
for /F "usebackq" %%I in (`PowerShell.exe "(Get-Date).AddDays(-1).ToString('ddMMyyyy')"`) do set "DateDaily=%%I"
for /F "usebackq" %%I in (`PowerShell.exe "(Get-Date).AddDays(-7).ToString('ddMMyyyy')"`) do set "DateWeekly=%%I"
rem set Date
rem Process now each file matching the wildcard pattern below in
rem current folder and calling a subroutine with current file name.
set "FileNotMoved=0"
for %%I in (*-*-*-*-*) do call :MoveToFolder "%%I"
endlocal & if not %FileNotMoved% == 0 pause
goto :EOF
rem This subroutine first gets fourth and fifth dash delimited part from
rem each passed double quoted file name.
rem Then it replaces in each fourth file name part each folder name part
rem by an empty string until either all folder name parts are processed
rem or the string substitution was successful meaning the file name part
rem really contains the folder name part.
rem Note: The substitution does not work correct if any folder name part
rem contains an equal sign as this character is the delimiter
rem between string to find and replace string for substitution.
rem In second case with substitution being successful the folder for
rem the file could be determined and the file is moved to the found
rem folder if also time part could be determined from file name.
:MoveToFolder
for /F "tokens=4,5 delims=-" %%A in ("%~1") do set "NamePart=%%A" & set "NameTime=%%B"
set "FolderIndex=0"
:FindFolder
if %FolderIndex% == %FolderCount% (
set "FileNotMoved=1"
echo Found no folder for: %1
goto :EOF
)
call set "CurrentPart=%%FolderPart%FolderIndex%%%"
if "!NamePart:%CurrentPart%=!" == "!NamePart!" (
set /A FolderIndex+=1
goto FindFolder
)
call set "CurrentFolder=%%FolderName%FolderIndex%%%"
if /I "%NameTime%" == "Daily" (
set "FolderTime=%DateDaily%"
) else if /I "%NameTime%" == "Weekly" (
set "FolderTime=%DateWeekly%"
) else (
set "FileNotMoved=1"
echo Undefined time for: %1
goto :EOF
)
mkdir "%CurrentFolder%\%NameTime%\%FolderTime%" 2>nul
move "%~1" "%CurrentFolder%\%NameTime%\%FolderTime%\" >nul
if errorlevel 1 (
set "FileNotMoved=1"
echo Failed to move file: %1
)
goto :EOF
The second batch code differs from first solution only on how subroutine MoveToFolder is coded for finding the corresponding folder for current file name. For that reason just the code of the subroutine is posted below.
:MoveToFolder
for /F "tokens=4,5 delims=-" %%A in ("%~1") do set "NamePart=%%A" & set "NameTime=%%B"
for /F "tokens=1* delims==" %%X in ('set FolderPart') do (
if not "!NamePart:%%Y=!" == "%NamePart%" (
set "FolderName=%%X"
goto FoundFolder
)
)
set "FileNotMoved=1"
echo Found no folder for: %1
goto :EOF
:FoundFolder
if /I "%NameTime%" == "Daily" (
set "FolderTime=%DateDaily%"
) else if /I "%NameTime%" == "Weekly" (
set "FolderTime=%DateWeekly%"
) else (
set "FileNotMoved=1"
echo Undefined time for: %1
goto :EOF
)
set "FolderIndex=%FolderName:~10%"
call set "CurrentFolder=%%FolderName%FolderIndex%%%"
mkdir "%CurrentFolder%\%NameTime%\%FolderTime%" 2>nul
move %1 "%CurrentFolder%\%NameTime%\%FolderTime%\" >nul
if errorlevel 1 (
set "FileNotMoved=1"
echo Failed to move file: %1
)
goto :EOF
For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
cd /?
echo /?
endlocal /?
for /?
goto /?
if /?
mkdir /?
move /?
pause /?
rem /?
set /?
setlocal /?
Read also the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul and >nul and answer on question Single line with multiple commands using Windows batch file for meaning of operator & on Windows command lines.
I have about 300 000 files in a directory. They are sequentially numbered - x000001, x000002, ..., x300000. But some of these files are missing and I need to write an output text file containing the missing file numbers. The following code does it only up to 10 000 files:
#echo off
setlocal enabledelayedexpansion
set "log=%cd%\logfile.txt"
for /f "delims=" %%a in ('dir /ad /b /s') do (
pushd "%%a"
for /L %%b in (10000,1,19999) do (
set a=%%b
set a=!a:~-4!
if not exist "*!a!.csv" >>"%log%" echo "%%a - *!a!.csv"
)
popd
)
How to extend it to 3 * 10^5 files?
Solution 1 - simple but slow
If all 300000 CSV files are in current directory on executing the batch file, this batch code would do the job.
#echo off
set "log=%cd%\logfile.txt"
del "%log%" 2>nul
for /L %%N in (1,1,9) do if not exist *00000%%N.csv echo %%N - *00000%%N.csv>>"%log%"
for /L %%N in (10,1,99) do if not exist *0000%%N.csv echo %%N - *0000%%N.csv>>"%log%"
for /L %%N in (100,1,999) do if not exist *000%%N.csv echo %%N - *000%%N.csv>>"%log%"
for /L %%N in (1000,1,9999) do if not exist *00%%N.csv echo %%N - *00%%N.csv>>"%log%"
for /L %%N in (10000,1,99999) do if not exist *0%%N.csv echo %%N - *0%%N.csv>>"%log%"
for /L %%N in (100000,1,300000) do if not exist *%%N.csv echo %%N - *%%N.csv>>"%log%"
set "log="
Solution 2 - faster but more difficult to understand
This second solution is definitely much faster than above as it processes the list of file names in current directory from first file name to last file name.
In case of last file is not x300000.csv, the batch code below just writes one more line into the log file with the information from which number to expected end number 300000 files are missing in current directory.
#echo off
setlocal EnableExtensions EnableDelayedExpansion
rem Delete log file before running file check.
set "log=%cd%\logfile.txt"
del "%log%" 2>nul
rem Define initial value for the number in the file names.
set "Number=0"
rem Define the file extension of the files.
set "Ext=.csv"
rem Define beginning of first file name with number 1.
set "Name=x00000"
rem Define position of dot separating name from extension.
set "DotPos=7"
rem Process list of files matching the pattern of fixed length in current
rem directory sorted by file name line by line. Each file name is compared
rem case-sensitive with the expected file name according to current number.
rem A subroutine is called if current file name is not equal expected one.
for /F "delims=" %%F in ('dir /B /ON x??????%Ext% 2^>nul') do (
set /A Number+=1
if "!Name!!Number!%Ext%" NEQ "%%F" call :CheckDiff "%%F"
)
rem Has last file not expected number 300000, log the file numbers
rem of the files missing in current directory with a single line.
if "%Number%" NEQ "300000" (
set /A Number+=1
echo All files from number !Number! to 300000 are also missing.>>"%log%"
)
endlocal
rem Exit this batch file to jump to predefined label EOF (End Of File).
goto :EOF
rem This is a subroutine called from main loop whenever current file name
rem does not match with expected file name. There are two reasons possible
rem with file names being in expected format:
rem 1. One leading zero must be removed from variable "Name" as number
rem has increased to next higher power of 10, i.e. from 1-9 to 10,
rem from 10-99 to 100, etc.
rem 2. The next file name has really a different number as expected
rem which means there are one or even more files missing in list.
rem The first reason is checked by testing if the dot separating name
rem and extension is at correct position. One zero from end of string
rem of variable "Name" is removed if this is the case and then the
rem new expected file name is compared with the current file name.
rem Is the perhaps newly determined expected file name still not
rem equal the current file name, the expected file name is written
rem into the log file because this file is missing in list.
rem There can be even more files missing up to current file name. Therefore
rem the number is increased and entire subroutine is executed once more as
rem long as expected file name is not equal the current file name.
rem The subroutine is exited with goto :EOF if the expected file name
rem is equal the current file name resulting in continuing in main
rem loop above with checking next file name from directory listing.
:CheckDiff
set "Expected=%Name%%Number%%Ext%"
if "!Expected:~%DotPos%,1!" NEQ "." (
set "Name=%Name:~0,-1%"
set "Expected=!Name!%Number%%Ext%"
)
if "%Expected%" EQU %1 goto :EOF
echo %Expected%>>"%log%"
set /A Number+=1
goto CheckDiff
For understanding the used commands in both solutions and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.
call /?
dir /?
echo /?
endlocal /?
for /?
if /?
goto /?
rem /?
set /?
setlocal /?
#echo off
setlocal EnableDelayedExpansion
for /F %%a in ('copy /Z "%~F0" NUL') do set "CR=%%a"
set "num=1000000"
del logfile.txt 2> NUL
< NUL (for %%a in (*.csv) do (
set /A num+=1
set /P "=!num:~1!!CR!"
if "x!num:~1!" neq "%%~Na" call :missingFile "%%~Na"
))
goto :EOF
:missingFile file
echo x%num:~1%.csv>> logfile.txt
echo x%num:~1%.csv Missing
set /A num+=1
if "x%num:~1%" neq "%~1" goto missingFile
exit /B