Batch script not processing remaining of the file after the goto step - batch-file

I have batch file that writes to the text file with the records. Each of this record needs to be processed from the file. For example if Name == KD then go to step 1 else continue with the next steps.
The issue after it goes to step 1, it exits the file. I need to come back to the next record to continue processing with DF. I did add label to the section to come back but it keeps processing only KD record.
Text file example:
Line Name Container
1 KD 123
2 DF 657
Code:
set txtfilepath=C:\Temp\Test.txt
set /a cnt=0
for /f %%a in ('type "%txtfilepath%"^|find "" /v /c') do set /a cnt=%%a
echo %txtfilepath% has %cnt% lines
for /f "skip=1 tokens=1,2,3,4,5* delims=,] " %%a in ('find /v /n "" ^< %txtfilepath%') do (
echo.%%b - this displays variable fine.
if %%b==DF (
set result=true
) else (
goto donotexecute
)
echo I am in true loop.
:donotexecute
echo i am in do not import loop
)
:Done
So the code goes in the donotexecute label and then I have no way to go back to my initial for loop to continue with the next line in the text file.

First, don't use set /a (evaluate arithmetic expression) if you just want to assign a value to an environment variable.
Environment variables are always of type string. On an arithmetic expression each number specified directly or hold by an environment variable is converted temporarily to a 32-bit signed integer for evaluation of the expression and the integer result is finally converted back to a string stored in the specified environment variable. So much faster is assigning the number string directly to the environment variable.
Second, Windows command processor does not support labels within a FOR loop. You need to use subroutines.
#echo off
set "txtfilepath=C:\Temp\Test.txt"
rem Don't know why the number of lines in the files must be determined first?
set "cnt=0"
for /F %%a in ('type "%txtfilepath%" ^| %SystemRoot%\System32\find.exe "" /v /c') do set "cnt=%%a"
echo %txtfilepath% has %cnt% lines.
for /F "usebackq skip=1 tokens=1-5* delims=,] " %%a in ("%txtfilepath%") do (
if "%%b" == "DF" (
call :ProcessDF "%%c"
) else if "%%b" == "KD" (
call :ProcessKD "%%c"
)
)
echo Result is: %result%
rem Exit processing of this batch file. This command is required because
rem otherwise the batch processing would continue unwanted on subroutine.
goto :EOF
rem This is the subroutine for name DF.
:ProcessDF
echo Processing DF ...
set "result=true"
echo Container is: %~1
goto :EOF
rem The command above exits subroutine and batch processing continues
rem on next line below the command line which called this subroutine.
rem This is the subroutine for name KD.
:ProcessKD
echo Processing KD ...
echo Container is: %~1
rem Other commands to process.
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 /?
echo /?
find /?
for /?
goto /?
if /?
rem /?
set /?
type /?
exit /B could be also used everywhere where goto :EOF is used as this is exactly the same. Run in a command prompt window exit /? for details. Sometimes on larger batch files it makes sense to use for example exit /B where used to exit processing of batch file and goto :EOF where used to just exit a subroutine.

Related

How can I use a batch file to selectively delete text in text files?

#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
::----------------------------------------------------------------------------------

Batch .txt reader

So, basically I want a Batch file to read a .txt. The problem is that the Batch file needs to update everytime a new line gets written to the .txt
#echo off
set "pc=%1"
FOR /F "delims=:" %%A IN ('findstr /N .* "%pc%"') DO set "zeilen=%%A"
type %pc%
set /A zeilen1=%zeilen%
:loop
if not %zeilen% == %zeilen1% (
set "line="
set zeilen2=%zeilen% - 1
for /f %%a in ('more/e +%zeilen2% ^< %pc%') do (
if not defined line set "line=%%a"
)
echo %line%
set /A zeilen+=1
)
FOR /F "delims=:" %%A IN ('findstr /N .* "%pc%"') DO set "zeilen1=%%A
goto loop
I also can't use the type command (line 9-13) because I don't want to refresh the whole .txt only the last line.
sry for my poor english
Thanks
To start the Batch you need to do something like this call batch.cmd txtname.txt
A basic tail command can be written like so. Credit to #dbenham for his initial solution on DosTips.com
#echo off
call :Loop <"tailme.txt"
exit
:Loop
set "line="
set /p "line="
if defined line (
echo %line%
) else (
pathping -q 1 -p 300 localhost >nul
)
goto :loop
If you don't wish to use third party options and wish to keep it pure batch, it is very possible. From your question, it sounds like you wish to read the last line of a text file and have it update that text each time the text file is edited. Further more, this batch file much be call'ed to when it needs to be used.
To do this, we can compare the date it was last modified using forfiles in an for loop. The reason for this is that if we use the file properties EX: ECHO Last-Modified Date : %%~ta we will not get the properties down to seconds. Thus the file will only compare down to the minutes.
Now that we can grab the last modified properties we can use an IF statement to look for when the file get a new time stamp. From there we can use a modified script that reads only the last line of a text file (Configurable by set /a LINES=LINES+1 LINES+1 - Infin) made by #Patrick Cuff
To call this batch file you will want to use call ReadFile.bat txtname.txt
Call - Command
ReadFile.bat - Name of batch script
txtname.txt - Name of textfile to read
Bellow is the full script.
ReadFile.bat
#ECHO OFF
#GOTO READ
:LOOP
Rem | Look for changes
FOR /f %%a in ('forfiles /M %1 /C "cmd /c echo #fdate-#ftime"') DO (set FileTimeCurrent=%%a)
IF "%FileTimeLoad%"=="%FileTimeCurrent%" (goto LOOP) else (goto READ)
:READ
cls
Rem | Get current date
FOR /f %%a in ('forfiles /M %1 /C "cmd /c echo #fdate-#ftime"') DO (set FileTimeLoad=%%a)
Rem | Get the number of lines in the file
set LINES=0
for /f "delims==" %%I in (%1) do (
set /a LINES=LINES+1
)
Rem | Print the last line
set /a LINES=LINES-1
more +%LINES% < %1
goto LOOP
For help on any of the commands do the following:
call /?
set /?
for /?
if /?
So on.

How to write a batch script to read a text file line by line,match it with a regex and then edit the line in the same file

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

How to move a long list of files to other directories?

I have a *.txt file that consist of a very long list of files (about 30k) to be moved and where each line contains the file name of the file to move with full path and the target folder with full path separated by the string  to .
List file example:
C:\USER\BDG\anto\12.jpg to D:\USER\BDG\,
C:\USER\SMG\kent\311.jpg to D:\USER\SMG\,
C:\USER\JKT\lydia\13121.jpg to D:\USER\JKT\,
C:\USER\NYC\tiffany\1e1b1.jpg to D:\USER\NYC\,
C:\USER\MNC\regent\1eb1be1.jpg to D:\USER\MNC\,
etc.
How to process this list file line by line to move all the files to specified folder?
The easiest method would have been opening the list file in a text editor with support for Perl regular expression find/replace and running a Perl regular expression replace all from top of file with search string ^(.+?) to (.+),$ and replace string #move "\1" "\2". The result would have been:
#move "C:\USER\BDG\anto\12.jpg" "D:\USER\BDG\"
#move "C:\USER\SMG\kent\311.jpg" "D:\USER\SMG\"
#move "C:\USER\JKT\lydia\13121.jpg" "D:\USER\JKT\"
#move "C:\USER\NYC\tiffany\1e1b1.jpg" "D:\USER\NYC\"
#move "C:\USER\MNC\regent\1eb1be1.jpg" "D:\USER\MNC\"
Then modified list file could have been saved next for example as MoveFiles.bat with ANSI encoding and executed with double clicking on it, or from within a command prompt window to see possible error messages in case of a file could not be moved for various reasons.
However, here is a small batch file for this task processing the list file ListFile.txt.
#echo off
if not exist "ListFile.txt" goto :EOF
setlocal EnableExtensions DisableDelayedExpansion
set "MoveError=0"
for /F "usebackq eol=| delims=" %%L in ("ListFile.txt") do call :ProcessFile "%%L"
if %MoveError% == 1 echo/ & pause
endlocal
goto :EOF
:ProcessFile
set "ListLine=%~1"
rem Remove comma at end of line if there is one at all.
if "%ListLine:~-1%" == "," set "ListLine=%ListLine:~0,-1%"
rem Replace " to " by a vertical bar being an invalid character in a file
rem name. The string " to " exists hopefully only once in each line.
set "ListLine=%ListLine: to =|%"
rem Split up the line into two substrings using | as delimiter.
rem First string is the file to move, second the target directory.
rem Execute the file move and output an error message on failure.
for /F "tokens=1,2 eol=| delims=|" %%I in ("%ListLine%") do (
move "%%~I" "%%~J" >nul 2>&1
if not errorlevel 1 goto :EOF
if %MoveError% == 1 echo/
echo ERROR: Failed to move the file
echo "%%~I"
echo to "%%~J"
set "MoveError=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 /?
echo /?
endlocal /?
for /?
goto /?
if /?
if /?
move /?
rem /?
set /?
setlocal /?
See also:
Microsoft support article Testing for a Specific Error Level in Batch Files
Microsoft TechNet article Using Command Redirection Operators
Stack Overflow answer on Where does GOTO :EOF return to?

My for loop with Yes/No give diverent output

Sometimes I press Y it goes to :no
And sometimes I press N it goes to :yes
What am I doing wrong?
Now the loop should go 3 times that's not the problem
Only the call is made is never good.
Hope someone can help me
CD %INSTALLDIR%
SET test=
FOR /f %%a in ('dir /b /o:-n') do (
SET test=%%a
ECHO Generate a answer file for %test%?
set INPUT=
set /P INPUT=[Y/N]:
IF /I '%INPUT%'=='y' call :yes
IF /I '%INPUT%'=='n' call :no
)
goto end
:yes
cd %test%
SET APPNAME=<%test%.options
for /f "tokens=1*" %%b in (%test%.options) do set OPTIONS=%%b
echo %APPNAME%
echo %OPTIONS%
goto end
:no
echo Skipping %%a
goto end
:end
ECHO NEXT
Every environment variable referenced with %VariableName% within a command block starting with ( and ending with matching ) is expanded during preprocessing of entire command block by Windows command interpreter before executing the command which finally executes the already preprocessed command block.
This means %INPUT% is replaced by the value of environment variable INPUT before command FOR is executed at all. The environment variable INPUT is not defined in the batch file above command FOR and so the comparisons in the command block depend on existence of this environment variable and its current value on starting the batch file.
Run in a command prompt window set /? and read the help output into the console window. The usage of delayed environment variable expansion is explained by the help on an IF and a FOR example on which command blocks are used usually.
But there is a better solution for this task then enabling delayed expansion. Instead of using set /P INPUT=[Y/N]: the command CHOICE is used which exits with an exit code assigned to ERRORLEVEL depending on key pressed by the user. In this case ERRORLEVEL is 1 if the user presses Y or y as being the first specified option or 2 if N or n is pressed by the user. Other values are not possible.
See also Microsoft support article Testing for a Specific Error Level in Batch Files explaining how ERRORLEVEL can be evaluated in a batch file even within a command block without usage of delayed expansion.
cd /D "%INSTALLDIR%"
for /F %%I in ('dir /AD /B /O:-N 2^>nul') do (
%SystemRoot%\System32\choice.exe /C YN /N /M "Generate an answer file for %%I [Y/N]? "
if errorlevel 2 (echo Skipping %%I) else call :GetOptions "%%I"
)
goto :EOF
:GetOptions
cd /D "%~1"
set APPNAME=<"%~1.options"
for /F "usebackq" %%J in ("%~1.options") do set "OPTIONS=%%J"
echo %APPNAME%
echo %OPTIONS%
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 /?
choice /?
dir /?
echo /?
for /?
goto /?
if /?
set /?
Read also the Microsoft article about Using Command Redirection Operators for an explanation of < and 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.
See also Where does GOTO :EOF return to?

Resources