I've set up an app for a couple of friends and me in batch with a auto-updating system, but I need to add a line of code in the auto-updating system. I decided to completely rewrite the file, it takes a long time to add 'echo' in from to every line and, '>>text.txt' at the end of every line and added '^' when needed, so I was wondering if there was an easier way of writing lot's of code to a file in batch.
Example:
#echo off
rem I need a way to do the following without adding 'echo' and '>>text.txt'
echo echo Checking for updates... >text.txt
echo echo 1.4 ^>^>new.txt >>text.txt
echo ping localhost -n 2 ^>nul >>text.txt
rem and so on and so on.
Or if there is a way to simply add a new line of code in a specific place in the file, that would also help!
Thanks in advance!
The following is how you can more easily and efficiently do what your current code does, by removing all of those individual write processes.
#( Echo #Echo Checking for updates...
Echo #(Echo 1.4^)^>^>"new.txt"
Echo #(%__AppDir__%ping.exe LocalHost -n 2^)^>NUL
)>"text.txt"
There are other possibilities, but at this time, based on the lack of information in your question, I'm reluctant to expand further at this time.
If I understand correctly, then you could do the following:
in the batch file, prepend each line of text that you want to output with :::: (this constitutes an invalid label that is going to be ignored);
then use the following code:
rem // Redirect to file:
> "text.txt" (
rem // Find all lines that begin with `::::` and loop over them:
for /F "delims=" %%T in ('findstr "^::::" "%~f0"') do (
rem // Store currently iterated line:
set "TEXT=%%T"
rem // Toggle delayed expansion to avoid loss of `!`:
setlocal EnableDelayedExpansion
rem // Remove `::::` prefix and output remaining line:
echo(!TEXT:*::::=!
endlocal
)
)
replace set "TEXT=%%T" by call set "TEXT=%%T" if you want to enable percent expansion within the returned text (so it could, for example, contain %~nx0, which would then be expanded to the file name of the script).
I am using this technique a lot (without the output redirection) for help systems in my batch files (/?).
Your asked
I need a way to do the following without adding echo and >>text.txt
The script takes advantage of the line continuation character, the caret ^.
The first character after the caret ^ is always escaped, so do linefeed characters:
#echo off
SETLOCAL EnableDelayedExpansion
call :init
>text.txt (
echo #echo off%NL%
Checking for updates...%NL%
>^>new.txt echo 1.4%NL%
>NUL ping localhost -n 2
)
ENDLOCAL
exit /b
:init
( set LF=^
%= 0X0D FORM FEED =%
)
::0X0A Carriage Return
FOR /F %%a in ('copy /Z "%~f0" nul') do set "CR=%%a"
::Create newline/line continuation character
set ^"NL=^^^%LF%%LF%^%LF%%LF%^^" %= Unix-Style Endings \n =%
::set ^"NL=%CR%^^^%LF%%LF%^%LF%%LF%^^" %= Windows-Style Endings \r\n =%
exit /b
The variable %LF% is a escaped linefeed, and %NL% is a escaped %LF% plus a escaped caret ^ for line continuation.
The code
>^>new.txt echo 1.4%NL%
>NUL ping localhost -n 2
might seem strange. Why isn't the first caret ^ escaped?
Because %NL% already escaped it.
Sources:
Explain how Windows batch newline variable hack works
https://stackoverflow.com/a/5642300/12861751
https://www.dostips.com/forum/viewtopic.php?t=6369
Related
I'm trying to run a query with a FOR loop and have each resulting variable line of the query output into it's own file.
I can't seem to get the delayed expansion variables to behave the way I want them to.
Basically I'm querying the printers installed on a print server and I want a .bat job containing certain text with the result output to multiple files containing the result name.
I think the problem is I'm not escaping some characters correctly, or I'm missing a % or ! on a variable, or some combination thereof.
#echo off
setlocal enabledelayedexpansion
FOR /F "tokens=1 delims=*" %%G IN ('wmic /node:PRINTSERVER printer get name') DO (
SET printer=%%G
SET printers=!printers: =!
SET printers=!printers:Name=!
ECHO ^(
#ECHO OFF
ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
ECHO.
ECHO ^"%windir%\system32\cscript %windir%\system32\prnmngr.vbs -ac -p \\PRINTSERVER\!printer!"^)>>!printer!.bat
)
endlocal
Expected results should be multiple files named PRINTERSHARENAME.bat
Each which contains:
#ECHO OFF
ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
ECHO.
%windir%\system32\cscript %windir%\system32\prnmngr.vbs -ac -p "\\PRINTSERVER\PRINTERSHARENAME"
EDIT
I will share more of my code. the wmic output contains spaces that had to be stripped, so this is why I used enabledelayedexpansion
EDIT2
Here is the output of my wmic command (Note that there are trailing spaces I've stripped out in the above code and the word 'Name' and a blank line at the end of the command):
C:\Users\bleepbloop>wmic /node:PRNTSVR printer get name
Name
PRINTER1
PRINTER2
OFFICEPRINTER
EDIT3
OK, I'm getting close. Here is code to reproduce, using an answer below:
(
echo Here is my first line
echo Here is my second line
echo Here is my third line
)>"textfile.txt"
FOR /F "delims=" %%G IN ('TYPE textfile.txt') DO (
(
ECHO #ECHO OFF
ECHO ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
ECHO ECHO.
ECHO "%%windir%%\system32\cscript" "%%windir%%\system32\prnmngr.vbs" -ac -p \\PRINTSERVER\%%G
)>%%G.bat
)
This works as expected and gives me 3 files named
Here is my first line.bat
Here is my second line.bat
Here is my third line.bat
however now I want to strip out all spaces from the variables output by textfile.txt, and for that I think I need to use delayed expansion?
So I want:
Hereismyfirstline.bat
Hereismysecondline.bat
Hereismythirdline.bat
I think I need to do this by using enabledelayedexpansion and inserting the following in the FOR loop:
SET variable=%%G
SET variable=!variable: =!
and then I have to insert the variable back into the loop properly. Still not sure how.
I want the file
Hereismyfirstline.bat
to contain
#ECHO OFF
ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
ECHO.
"%windir%\system32\cscript" "%windir%\system32\prnmngr.vbs" -ac -p \\PRINTSERVER\Hereismyfirstline
and the next file
Hereismysecondline.bat
to contain:
#ECHO OFF
ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
ECHO.
"%windir%\system32\cscript" "%windir%\system32\prnmngr.vbs" -ac -p \\PRINTSERVER\Hereismysecondline
I suggest this batch code for this task:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "skip=1 eol=| tokens=*" %%I in ('%SystemRoot%\System32\wbem\wmic.exe /node:PRINTSERVER printer get name 2^>nul') do (
for /F "eol=| delims= " %%J in ("%%I") do (
set Printer=%%~nxJ
if defined Printer (
echo #echo off
echo echo PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
echo echo/
echo "%%SystemRoot%%\system32\cscript.exe" "%%SystemRoot%%\system32\prnmngr.vbs" -ac -p "\\PRINTSERVER\%%~nxJ"
)>"%%~nxJ.bat"
)
)
endlocal
Note: After delims= on second for command line must be a horizontal tab character and not one or more spaces as displayed by the web browsers according to HTML standard for the tab character.
Processing output of wmic is problematic because of this application outputs data always Unicode encoded using UTF-16 Little Endian encoding and for has a quirks on processing this Unicode output correct. For more details see for example How to correct variable overwriting misbehavior when parsing output?
The outer for processes the output of wmic with skipping first line containing heading Name. For all other non-empty lines all leading normal spaces and horizontal tabs are removed before assigning the rest of the line to specified loop variable I even on starting very unusual with a semicolon. | is not allowed in a printer name, but ; would be allowed although having never seen a printer name starting with ;.
The inner for with horizontal tab character as delimiter processes the printer name which can contain one or more spaces, but not a tab character. The printer name with all trailing horizontal tabs removed is assigned to specified loop variable J.
The remaining string is the printer name with trailing normal spaces. Windows prevents usually the creation of a file with trailing spaces. For that reason is assigned to environment variable Printer with using %%~nxJ just the printer name without trailing spaces. But spaces inside the printer name are kept by this command.
A single carriage return caused by the for quirks on processing of output of wmic results in getting environment variable Printer deleted instead of being defined with the carriage return.
So if the environment variable Printer is really defined with a printer name containing no, one or even more spaces, but no leading spaces/tabs and no trailing spaces/tabs, the batch file can be created with using printer name as assigned to loop variable J in batch file and in batch file name using %%~nxJ.
So there is no delayed environment variable expansion needed which makes this batch file working also for a printer name containing an exclamation mark.
See also DosTips forum topic ECHO. FAILS to give text or blank line - Instead use ECHO/ for the reason writing into the created batch files echo/ instead of echo..
This batch code uses delayed expansion inside the inner loop to remove all spaces from printer name for the batch file name.
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for /F "skip=1 eol=| tokens=*" %%I in ('%SystemRoot%\System32\wbem\wmic.exe /node:PRINTSERVER printer get name 2^>nul') do (
for /F "eol=| delims= " %%J in ("%%I") do (
set "Printer=%%~nxJ"
if defined Printer (
setlocal EnableDelayedExpansion
set "BatchFileName=!Printer: =!"
(
echo #echo off
echo echo PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
echo echo/
echo "%%SystemRoot%%\system32\cscript.exe" "%%SystemRoot%%\system32\prnmngr.vbs" -ac -p "\\PRINTSERVER\!Printer!"
)>"!BatchFileName!.bat"
endlocal
)
)
)
endlocal
It is absolutely no problem to run a batch file with one or more spaces in file name on enclosing entire batch file name in double quotes like any other file/folder name containing a space or one of these characters &()[]{}^=;!'+,`~. But this second batch file code demonstrates that it is possible to create the batch files with no spaces in file name while exclamation marks in printer name are nevertheless processed correct.
This code is slower than first code because of usage of setlocal and endlocal inside the loop. Read this answer for details about the commands setlocal and endlocal and what happens on every usage of these two commands in background making the second variant slower than the first variant.
Note: The printer name inside the batch file is with spaces. Just the batch file name is without spaces. But that can be easily changed if needed.
Parenthesis can group commands, but not split arguments. So, instead of ECHO (..., do:
SET printer=%%G
(
ECHO #ECHO OFF
ECHO ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
ECHO ECHO.
ECHO ^"%windir%\system32\cscript %windir%\system32\prnmngr.vbs -ac -p \\PRINTSERVER\!printer!"
)>!printer!.bat
Replaced >> with > which will create new files for each printer, instead of
appending more commands to existing files.
Noticed also you don't need delayed expansion, and probably "delims=" is more adequate.
Overall, your code may be rewritten as:
FOR /F "delims=" %%G IN ('wmic /node:PRINTSERVER printer get name') DO (
(
ECHO #ECHO OFF
ECHO ECHO PLEASE WAIT WHILE YOUR PRINTER IS INSTALLED
ECHO ECHO.
ECHO "%%windir%%\system32\cscript" "%%windir%%\system32\prnmngr.vbs" -ac -p \\PRINTSERVER\%%G
)>%%G.bat
)
So, I have no clue on how to have CMD echo lines from a *.txt text file one at a time with a tiny delay to make it seem like it's processing.
Is this even possible with a batch alone?
I've tried doing research, but I can't find sufficient text manipulation to be able to do this, but I do know how to make a pause between each command and how to do loops.
Let us assume the text file TestFile.txt should be output line by line which is an ANSI encoded text file with just ASCII characters containing this text:
Line 1 is with nothing special. Next line 2 is an empty line.
;Line 3 with a semicolon at beginning.
Line 4 has leading spaces.
Line 5 has a leading horizontal tab.
Line 6 is with nothing special. Next line 7 has just a tab and four spaces if used internet browser does not remove them.
Line 8 is ! with exclamation marks ! in line!
? Line 9 starts with a question mark.
: Line 10 starts with a colon.
] Line 11 starts with a closing square bracket.
The batch file below outputs this text file line by line with one second delay between each line with the exception of second line which is completely empty.
#echo off
title Read line by line with delay
setlocal EnableExtensions DisableDelayedExpansion
rem Use command TIMEOUT by default for 1 second delay. But use
rem PING in case of TIMEOUT does not exist as on Windows XP.
set "DelayCommand=%SystemRoot%\System32\timeout.exe /T 1 /NOBREAK"
if not exist %SystemRoot%\System32\timeout.exe set "DelayCommand=%SystemRoot%\System32\ping.exe 127.0.0.1 -n 2"
for /F "usebackq eol=¿ delims=" %%I in ("TestFile.txt") do (
echo(%%I
%DelayCommand% >nul
)
endlocal
pause
The strange looking character ¿ after eol= is an inverted question mark with hexadecimal Unicode value 00BF used to output third line correct. A line with an inverted question mark at beginning would not be output because of this redefinition of end of line character.
This batch file code is not designed to output any type of text file with any type of character encoding independent on which characters contains the text file. The Windows command line environment is not designed for output of any text file.
It is also possible to use a different, unquoted syntax to specify the FOR options delims, eol and usebackq to define an empty list of delimiters and no end of line character:
#echo off
title Read line by line with delay
setlocal EnableExtensions DisableDelayedExpansion
rem Use command TIMEOUT by default for 1 second delay. But use
rem PING in case of TIMEOUT does not exist as on Windows XP.
set "DelayCommand=%SystemRoot%\System32\timeout.exe /T 1 /NOBREAK"
if not exist %SystemRoot%\System32\timeout.exe set "DelayCommand=%SystemRoot%\System32\ping.exe 127.0.0.1 -n 2"
for /F usebackq^ delims^=^ eol^= %%I in ("TestFile.txt") do (
echo(%%I
%DelayCommand% >nul
)
endlocal
pause
Thanks goes to aschipfl for this alternate syntax of the three FOR options with using escape character ^ to escape the equal signs and spaces in not double quoted options string to get interpreted by cmd.exe the string usebackq delims= eol= as one argument string for for /F.
There is ( instead of a space as usually used to output also correct line 7 with just a tab and some normal spaces. See also DosTips forum topic ECHO. FAILS to give text or blank line - Instead use ECHO/. echo/%%I does not correct output line 9 starting with a question mark.
It is not possible to define with an option that FOR does not ignore empty lines. But it is possible with FIND or FINDSTR to output a text file with all lines with a line number at beginning and so having no empty line anymore. The line number is enclosed in square brackets (FIND) or separated with a colon (FINDSTR) from rest of the line. It would be possible to assign to loop variable only the string after first sequence of ] or : after line number which in most cases means the entire line as in text file. But if a line in text file starts by chance with ] or :, FOR would remove this delimiter character too. The solution is this code:
#echo off
title Read line by line with delay
setlocal EnableExtensions DisableDelayedExpansion
rem Use command TIMEOUT by default for 1 second delay. But use
rem PING in case of TIMEOUT does not exist as on Windows XP.
set "DelayCommand=%SystemRoot%\System32\timeout.exe /T 1 /NOBREAK"
if not exist %SystemRoot%\System32\timeout.exe set "DelayCommand=%SystemRoot%\System32\ping.exe 127.0.0.1 -n 2"
for /F delims^=^ eol^= %%I in ('%SystemRoot%\System32\findstr.exe /N "^" "TestFile.txt" 2^>nul') do (
set "Line=%%I"
setlocal EnableDelayedExpansion
echo(!Line:*:=!
endlocal
%DelayCommand% >nul
)
endlocal
pause
FINDSTR searches in the specified file with the regular expression ^ for matching lines. ^ means beginning of a line. So FINDSTR does not really search for a string in the lines of the file because of every line in a file has a beginning, even the empty lines. The result is a positive match on every line in the file and therefore every line is output by FINDSTR with the line number and a colon at beginning. For that reason no line processed later by for /F is empty anymore because of all lines start now with a line number and a colon, even the empty lines in the text file.
2^>nul is passed to cmd.exe started in background as 2>nul and results in redirecting an error message output by FINDSTR to handle STDERR to the device NUL to suppress the error message. FINDSTR outputs an error message if the file to search does not exist at all or the file cannot be opened for read because of missing NTFS permissions which allow that or because of the text file is currently opened by an application which denies the read access to this file as long as being opened by the application.
cmd.exe processing the batch file captures all lines output by FINDSTR to handle STDOUT of cmd.exe started in background and FOR processes now really all lines in the file after FINDSTR finished and the background command process closed itself.
The entire line with line number and colon output by FINDSTR executed in a separate command processes started by FOR with %ComSpec% /c and the command line within ' as additional arguments is assigned to loop variable I which is assigned next to environment variable Line.
Then delayed expansion is enabled as needed for next line which results in pushing address of current environment variables list on stack as well as current directory path, state of command extensions and state of delayed expansion before creating a copy of the current environment variables list.
Next the value of environment variable Line is output, but with substituting everything up to first colon by nothing which results in the output of the real line as stored in text file without the line number and the colon inserted at beginning by FINDSTR.
Finally the created copy of environment variables list is deleted from memory, and previous states of delayed expansion and command extension are popped from stack and set as well as the current directory path is set again as current directory and previous address of environment variables list is restored to restore the list of environment variables.
It is of course not very efficient to run for each line in text file the commands setlocal EnableDelayedExpansion and endlocal doing much more than just enabling/disabling delayed expansion, but this is necessary here to get lines with an exclamation mark correct assigned to environment variable Line and process next correct the value of Line. The efficiency loss is not really problematic here because of the delay of one second between output of each line.
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 /?
findstr /?
for /?
if /?
ping /?
rem /?
set /?
setlocal /?
Despite your question being off topic, I have decided to include this because, there are already two answers and it can be achieved using a single line.
From a batch file:
#For /F Tokens^=1*Delims^=]^ EOL^= %%A In ('Find /N /V ""^<"C:\test.txt"') Do #Echo(%%B&>Nul PathPing 127.0.0.1 -n -q 1 -p 450
From the Command Prompt:
For /F Tokens^=1*Delims^=]^ EOL^= %A In ('Find /N /V ""^<"C:\test.txt"') Do #Echo(%B&>Nul PathPing 127.0.0.1 -n -q 1 -p 1350
Both examples do not omit empty lines from your source file, C:\test.txt, which can be changed as required.I have used PathPing for the 'tiny delay', because it seems more controllable; to adjust the delay all you need to do is change the last number until you find your most pleasing output.
Give a try for this batch script :
#echo off
Title Read line by line with delay
set "InputFile=TestFile.txt"
set "delay=1" Rem Delay one seconds, you can change it for your needs
setlocal enabledelayedexpansion
for /f "tokens=*" %%A in ('Type "%InputFile%"') do (
set /a N+=1
set "Line[!N!]=%%A"
)
for /l %%i in (1,1,%N%) do (
echo !Line[%%i]!
Timeout /T %delay% /nobreak>nul
)
pause
I have to run an executable (written in C#) 42 times separately for 42 US states on Windows command line. I wrote a batch file to automate the process. The 1st user input to the executable is 1, and the 2nd one is the state abbreviation (AL, AZ, CT etc.). I have written the following script to do it:
#echo off
for /f "tokens=1 delims=" %%x in (CropHailStates.txt) do (
(echo 1 & echo %%x)|Z:\Models\LossCalc.exe
)
Each row in CropHailStates.txt file contains the state abbreviation as follows:
AL
AZ
CT
Now in manual mode, when 1 is entered at the 1st prompt and AL is entered at the 2nd, the C# program reads a file named "AL.Even.CropLoss.csv". But when I run the batch script to do it automatically, I get the error message saying that the file "AL .Even.CropLoss.csv" is not found. The problem is related to the extra whitespace after AL. It’s somehow adding the whitespace after inserting the state abbreviation. It’s like pressing the spacebar after writing the state abbreviation, but before pressing enter.
How can I get rid of that extra whitespace in the file name?
The problem is an artifact of the pipe parser when dealing with a parenthesized block of code.
The source of the problem is described by jeb at Why does delayed expansion fail when inside a piped block of code?.
Each side of the pipe is executed in a new CMD /C process.
When a multi-line parenthesized block gets piped, the parser must repackage the entire block into a single line so that it can be executed via CMD /C
(
echo line 1
echo line 2
) | findstr "^"
The left side of the pipe is executed as:
C:\WINDOWS\system32\cmd.exe /S /D /c" ( echo line 1 & echo line 2 )"
You can see the extra spaces that are introduced.
Even though your code is already on a single line, it still goes through the same parser that introduces those pesky spaces.
I know of three relatively simple solutions that eliminate the unwanted spaces without the need for a temporary file.
1) Add an extra CMD /C where you explicitly get the exact behavior you are looking for
#echo off
for /f "tokens=1 delims=" %%x in (CropHailStates.txt) do (
cmd /c "echo 1&echo %%x"|Z:\Models\LossCalc.exe
)
2) Store part of the command in a variable and delay expansion until execution of CMD /C
#echo off
setlocal
for /f "tokens=1 delims=" %%x in (CropHailStates.txt) do (
set "cmd=&echo %%x"
(echo 1%%cmd%%)|Z:\Models\LossCalc.exe
)
3) Introduce delayed expansion of a linefeed variable - a mind blowing technique developed by jeb that he describes in that same SO link that I provided
#echo off
setlocal
set ^"LF=^
%= This creates a linefeed character =%
"
for /f "tokens=1 delims=" %%x in (CropHailStates.txt) do (
(echo 1%%LF%%echo %%x%%LF%%)|Z:\Models\LossCalc.exe
)
(echo 1& echo %%x)>tempfile.txt
Z:\Models\LossCalc.exe <tempfile.txt
del tempfile.txt
should provide the data without the trailing spaces
To get rid of the last character (the whitespace) you can do:
#echo off
setlocal EnableDelayedExpansion
for /f "tokens=1 delims=" %%x in (CropHailStates.txt) do (
set "result=%%x"
(echo 1 & echo !result:~0,-1!)|Z:\Models\LossCalc.exe
)
Hope it helps.
So, I've been trying to create a simple spinning line thing that goes on for a set number of loops. I've encountered a problem: I can't find a way to add to a variable, or have a loop counter. This is my code so far (Other general criticisms are accepted too: I'm new to this and it all helps.)
#echo off
:1
echo
echo
echo
echo -
echo
cls
echo
echo
echo /
echo
cls
echo
echo
echo I
echo
cls
echo
echo
echo \
echo
cls
echo
echo
echo -
echo
IF %timer%
goto 1
pause
Really sorry if it's already been asked; I just can't seem to find what I'm looking for. Also, it's very possible this could just be a simple command, in which case i apologise again.
There's a couple of errors with your code as it stands.
The major one is
IF %timer%
goto 1
Batch is a ver old-fashioned language and is very particular about syntax. You can get a syntax description by typing
if /? |more
at the prompt. (replace if with the keyword you desire)
if requires
if string1==string2 thingtodoiftrue
Over the years, the syntax has been expanded, still maintaining the old version for compatibility so that the general form is now
if string1==string2 (thingtodoiftrue) else (thingtodoiffalse)
where == may now be a number of operators (equ, neq, ...); you can add a /i switch to make the strings case-insensitive, or a not keyword to reverse the sense. The parentheses are optional if the thingtodo is a single statement.
There are some quirky syntax requirements however. Either thingtodoiftrue or ( must be on the same physical line as the if keyword. The sequence ) else ( must all be on one physical line (if it's used)
As for performing some variety of count using your original structure, there are many ways. Here's one:
#echo off
set count=15
:1
....
set /a count=count-1
IF %count% neq 0 goto 1
pause
This may be what you are looking for. This runs the code 10000 times and it could be modified according to your need.
#echo off
for /l %%i in (1,1,10000) do (
echo -
cls
echo /
cls
echo I
cls
echo \
cls
)
Cheers, G
#echo off
setlocal enableextensions disabledelayedexpansion
rem Get a 0x13 character (carriage return) char inside a variable
for /f %%a in ('copy /Z "%~f0" nul') do set "CR=%%a"
rem Spin the line
setlocal enabledelayedexpansion
for /l %%a in (1 1 5000) do for %%b in (- \ ^| /) do (
set /a "pct=%%a / 50"
<nul set /p ".=%%b !pct!%% !cr!"
)
endlocal
The basic idea is to output the spinning element, followed by the percentage. To keep all the output in the same line
<nul set /p "var=outputtext"
is used. This echoes the indicated text to console, waits for input, that is readed from nul, ending the prompt wait and continues without moving the cursor to the next line. There is no line feed
Now, it is necessary overwrite this line with the new information each time. To do it, it is necessary to get a carriage return character into a variable. For it, the for /f is used, retrieving the needed carriage return character from the output of the copy command.
note: the disabledelayedexpansion is necessary in this step to avoid problems if the full path/filename of the batch file (%~f0) contains any exclamation character.
The remaining code just iterates painting the corresponding character in the list, calculating the percentage to output and printing all to the console, without the line feed (<nul set /p ...) but with an aditional carriage return that moves the cursor to the start of the line. So, the next output will overwrite the previous one
note: in this case, enabledelayedexpansion is needed to get access to the content of the changed percentage variable and to output the carriage return. Without delayed expansion active, the parser removes the carriage return from the output.
I have a script in which I read html files which I want to edit. Here I paste the code which calls :remove_redundant_columns subroutine.
It should remove the spaces/white spaces from begin of each line and remove from html file. Only problem is that it adds extra text like = to lines which are almost empty, just have few tabs.
The html file which I downloaded is from hidemyass.com/proxy-list/1
call parse_proxy.bat remove_redundant_columns !FILENAME!
exit /b
:remove_redundant_columns
REM Remove whitespaces from begin of lines and <span></span>
FOR /f "tokens=*" %%t in (%1) do (
SET S=%%t
SET S=!S:^<span^>^</span^>=!
if NOT "!S!"=="" >>$tmp$ echo !S!
)
del %1
REN $tmp$ %1
exit /b
If you believe, that's your only problem... You need to check, if your variable S contains content.
That's required, as substitution on an undefined variable will not produce an undefined/empty variable, the new content will be the substitution text.
:remove_redundant_columns
REM Remove whitespaces from begin of lines and <span></span>
FOR /f "tokens=*" %%t in (%1) do (
SET S=%%t
if defined S (
SET S=!S:^<span^>^</span^>=!
>>$tmp$ echo !S!
)
)
As dbenham stated, you got many other problems,
and one additional problem is the echo !S! command itself.
ECHO has some nasty side effects on different content.
If the content is empty (or only spaces) then it will print it's currently state
ECHO IS OFF
If the content is OFF or ON it will NOT be echoed, it will only change the state.
And if the content is /? it will echo the help instead of /?.
To solve this you could simply change ECHO !S! to ECHO(!S! and all problems are gone.
jeb already solved your = problem (once the extra IF DEFINED check is added to his answer). But you may have at least one other problem.
I agree with Joey that you should not be using batch to manipulate HTML like this. But, if you really want to...
Your potential problem is that HTML usually has ! characters sprinkled within. Your code uses delayed expansion, but that causes corruption of FOR variable expansion when it contains ! character(s). The solution is to toggle delayed expansion on and off within your loop.
:remove_redundant_columns
setlocal disableDelayedExpansion
REM Remove whitespaces from begin of lines and <span></span>
(
FOR /f "usebackq eol= tokens=*" %%t in ("%~1") do (
SET S=%%t
setlocal enableDelayedExpansion
if defined S SET "S=!S:<span></span>=!"
for /f "eol= tokens=*" %%S in ("!S!") do if "%%S" neq "" echo %%S
endlocal
)
) >>$tmp$
move /y $tmp$ "%~1"
exit /b
Other minor changes that were made to the code:
The search and replace can be simplified by using quotes so that special chars don't need to be escaped.
You can replace DEL and REN with a single MOVE.
Redirection is more efficient (faster) if you redirect once using an outer set of parentheses
You may need to search a file name that has spaces and or special characters, in which case you will need to quote the name. But that requires the FOR /F "USEBACKQ" option.
EDIT
Modified code to strip leading spaces after <span></span> has been replaced to eliminate potential of a line containing nothing but spaces and/or tabs.
Also set EOL to space to prevent stripping of lines beginning with ;