BATCH - Remove "" and line diference in batch - file

I need a little help here,
How can i remove all the " from the first line without touching the second line and then join the two lines as one?
This is in a txt file and i need the change to be made in it.
line1->
curl "https://localhost:1234/wle//505?action=god&params="
line 2-> with more than 9000 characters
{"some text to join after params= that contains" and {}[]/,:"}
Hope someone can help.
Thanks

#echo off
setlocal EnableDelayedExpansion
< input.txt (
set /P "line="
< NUL set /P "=!line:"=!"
findstr "^"
) > output.txt
move /Y output.txt input.txt

edited to match comment 9000 characters, and cmd cant hold that many characters (simple: write first line without line feed, add second line):
(if there still are too many characters, jrepl.bat can help)
#echo off
setlocal enabledelayedexpansion
<c.txt (
set /p "line1="
set /p "line2="
)
<nul >c.txt set /p "=!line1:"=!"
>>c.txt echo %line2%
read the two lines into two variables, write both back to file, removing the quotes from the first one.
Note: Delayed expansion might/might not be needed for each of the variables (maybe separately), depending on present characters. (here the & in the first line needs delayed expansion).
another edit to match only the second line. Process the first line as above. For the second line, just use more +1. This will work regardless of the line length. Contra: you have to use a secondary file. Pro: no problems with special chars (in the second line).
#echo off
setlocal enabledelayedexpansion
<c.txt set /p "line1="
<nul >c.out set /p "=!line1:"=!"
more +1 c.txt >>c.out
move /y c.out c.txt

Related

Writing to a file in batch

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

Combine lines in text file using batch

I want to make a program that takes the content of the second line of a text file and puts it on the first. (It doesn't matter if the second doesn't get edited)
for /f "tokens=1" %%t in (file.txt) do set string1=%%t
for /f "tokens=2" %%t in (file.txt) do set string2=%%t
echo %string1%%string2%>file.txt
I have two issues hat I can't seem to be able to fix.
One: the loops only include the first word of each line in the variables.
Two: Echo doesn't replace the first line of the file with the variables given and instead writes ECHO command deactivated (I have the French version of Windows 10 and simply translated what got written in the file, the text in English Windows version might be slightly different, but you get the idea)
If you have any suggestions, I would appreciate if you explain what the code you provide does (I always like to learn)
Your question is not clear and can be understood in several different ways. Anyway, this management is simpler with no for command:
#echo off
setlocal EnableDelayedExpansion
< file.txt (
rem Takes the content of the first line
set /P "line1="
rem Takes the content of the second line and puts it on the first
set /P "line2="
echo !line1!!line2!
rem It doesn't matter if the second line doesn't get edited
echo !line2!
rem Copy the rest of lines
findstr "^"
) > output.txt
move /Y output.txt file.txt
The FOR command uses a space as a delimiter by default. So you have to tell it to not use any delimiters with the DELIMS option. Also, you should be able to do this with a single FOR /F command. Just hold the previous line in a variable.
#ECHO OFF
setlocal enabledelayedexpansion
set "line1="
(for /f "delims=" %%G in (file.txt) do (
IF NOT DEFINED line1 (
set "line1=%%G"
) else (
echo !line1!%%G
set "line1="
)
)
REM If there are an odd amount of lines, line1 will still be defined.
IF DEFINED line1 echo !line1!
)>File2.txt
EDIT: I think I completely misunderstood your question. Once you clarify your question I will repost a code solution if needed.
Use skip to omit the first line and write the 2nd line twice. In general an edit of a file implies a rewrite to a new file and possibly a rename to retain the old file name.
:: Q:\Test\2018\07\25\SO_51508268.cmd
#Echo off
Set "flag="
( for /f "usebackq skip=1 delims=" %%A in ("file1.txt") Do (
If not defined flag (
Echo=%%A
Set flag=true
)
Echo=%%A
)
) >file2.txt
Del file1.txt
Ren file2.txt file1.txt
After running the batch a file1.txt with initially numbered lines 1..5 looks like this:
> type file1.txt
2
2
3
4
5

How to read and print contents of text file line by line?

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

Batch file to read first line of text that hasn't been used, and then mark as used

I have a requirement to, within a windows batch file, read the first available line from a text file, pass it to a variable and mark the name\line as used
An example of the file is below.
apple
pear
orange
The script would start with 'apple', pass 'apple' to a variable to be used later in the script (I know how to do that bit), and then write back that line to read &apple, the '&' works as a marker to say it's been used.
The file would then look like:
&apple
pear
orange
the next time the batch file is run it would take 'pear', pass it to a variable and mark it with a & making it look like:
&apple
&pear
orange
I started by trying to find '&' and then trying to move to the next line, but I'm failing after about 12 hours of trying. This is what I got so far .. not much:
for /f "tokens=1" %l in ('name.txt') do (Find /v "&" /v "^---- ^$") (For /F %n in (%l) do (set NewName=%n))
Thanks
Running this on the.file would modify each line in turn;
#echo off
setlocal enabledelayedexpansion
type nul > the.file.temp
set last=
for /F "tokens=*" %%A in (the.file) do (
set line=%%A
if "!line:~0,1!" neq "&" if "!last!" equ "" (
set last=!line!
set line=^&!line!
)
echo !line! >> the.file.temp
)
echo last value is !last!
type the.file.temp > the.file
(If the line does not begin with & and the variable last is empty, put the line in last & modify line with a leading &. Always append line to a temp file, renaming when done)
Alex k. has a good answer that is probably fine for most situations. (I upvoted.)
However, it will corrupt any text containing !. That limitation can be fixed by toggling delayed expansion on and off within the loop.
The solution is likely to be fast enough for most reasonably sized files. But a FOR loop can become quite slow for large files.
I tested a 190kb file containing 2817 lines, and the Alex K. solution took 20 seconds for one run.
Here is a completely different solution without using any loops that processes the same 190kb file in 0.07 seconds - 285 times faster :)
#echo off
setlocal enableDelayedExpansion
set "file=test.txt"
findstr /bv "$ &" "%file%" >"%file%.available"
set "var="
<"%file%.available" set /p "var="
if defined var (
>"%file%.new" (
findstr /b "&" "%file%"
<nul set /p "=&"
type "%file%.available"
)
move /y "%file%.new" "%file%" >nul
)
del "%file%.available"
echo var=!var!
Update: As requested in comment, here is a heavily commented version of the code.
#echo off
setlocal enableDelayedExpansion
:: Define the file to process
set "file=test.txt"
:: Write the unused lines to a temporary "available" file. We don't want any
:: empty lines, so I strip them out here. There are two regex search strings;
:: the first looks for empty lines, the second for lines starting with &.
:: The /v option means only write lines that don't match either search string.
findstr /bv "$ &" "%file%" >"%file%.available"
:: Read the first available line into a variable
set "var="
<"%file%.available" set /p "var="
:: If var defined, then continue, else we are done
if defined var (
REM Redirect output to a "new" file. It is more efficient to redirect
REM the entire block once than it is to redirect each command individulally
>"%file%.new" (
REM Write the already used lines to the "new" file
findstr /b "&" "%file%"
REM Append the & without a new line
<nul set /p "=&"
REM Append the unused lines from the "available" file. The first appended
REM line is marked as used because of the previously written &
type "%file%.available"
)
REM Replace the original file with the "new" content
move /y "%file%.new" "%file%" >nul
)
:: Delete the temp "available" file
del "%file%.available"
:: Display the result
echo var=!var!
I haven't tested this, but I just realized I could have written the line that writes the available lines to look for lines that start with a character other than &:
findstr "^[^&]" "%file%" >"%file%.available"

Multiline text file, how to put into an environment variable

i have a file called file.txt which contains:
this is line one ^
this is line two ^
this is the last line
how can i put that into an env var?
i can do this from a batch file:
test.bat
set LF=^
[blank line]
[blank line]
rem two blank lines needed above
set multi=Line 1!LF!Line 2!LF!Last line
echo !multi!
this outputs three lines:
Line 1
Line 2
Last line
so how can i get file.txt into envvar inside a batch file?
As dbenham said, it can be done also with for/f but it's a bit more complicated.
The simple 80% solution is
setlocal EnableDelayedExpansion
set "var="
set LF=^
rem *** Two empty lines are required for the linefeed
FOR /F "delims=" %%a in (myFile.txt) do (
set "var=!var!!LF!%%a"
)
echo !var!
But it fails with:
- If a line is blank it will be skipped
- If a line begins with ; the EOL-character
- If a line contains ! (and carets)
But then you could use a bit more complex solution
#echo off
SETLOCAL DisableDelayedExpansion
set "all="
FOR /F "usebackq delims=" %%a in (`"findstr /n ^^ aux1.txt"`) do (
set "line=%%a"
SETLOCAL EnableDelayedExpansion
set "line=!line:#=#S!"
set "line=!line:*:=!"
for /F "delims=" %%p in ("!all!#L!line!") do (
ENDLOCAL
set "all=%%p"
)
)
SETLOCAL EnableDelayedExpansion
if defined all (
set "all=!all:~2!"
set ^"all=!all:#L=^
!"
set "all=!all:#S=#!"
)
echo !all!
What the code do?
First, the findstr /n ^^ will prepend each line with a line number and a colon, like
1:My first Line
2:; beginning with a semicolon
3:
4:there was an empty line
This solves the problem of empty lines and also the standard EOL-character ; can be ignored.
To get the content of the line, the value is set to a variable while delayed expansion is disabled, this solves the problem with ! and ^ characters.
To remove the line number and the colon, the delayed expansion will be enabled (no, a delim of : can't solve it).
Then all # are replaced with #S, this will be done first, as after the prefix removing the line could be empty and the replacement would fail.
But why I replace it?
That's because I can't insert the linefeeds here, as the following FOR/F would fail with embedded linefeeds,
so I only add linefeed marker (in this case I use #L), but the content of the file could contain also a #L, but by replacing all # with #S all markers are unique.
After the marker, there is the problem to close/disable the delayed expansion with an endlocal, but preserve the content of the modified all and line variable.
This is done with the FOR/F-endlocal trick, as the %%p can transport content behind the endlocal barrier.
Then after reading the complete file, I check if the all is defined, as it would be empty for an empty file.
Then the first linefeed marker #L will be removed, and all other markers are replaced with a real linefeed character.
Then the sharp safer #S will be reverted to #.
That's all, so even this solution is obviously...
You were almost there. You need to read each line of text and then append the line plus a line feed to the variable.
FOR /F could be used, but it doesn't play well with delayed expansion if the content contains ! characters. It is also awkward to preserve blank lines and awkward to disable the EOL option.
A simpler solution is to use SET /P to read the lines. The limitations with this technique are:
1) It trims trailing control characters from each line
2) The file must use Windows standard line terminators of carriage return, line feed. It will not work with Unix style line feed.
3) It is limited to reading 1023 bytes per line (not including the line terminator characters)
Bear in mind that an environment variable can only hold a little less than 8 kbytes of data. So you are limited to only loading a very small file into a variable with this technique.
#echo off
setlocal enableDelayedExpansion
set LF=^
:: Two blank lines above needed for definition of LF - do not remove
set file="test.txt"
set "var="
for /f %%N in ('find /c /v "" ^<%file%') do set lineCnt=%%N
<%file% (
for /l %%N in (1 1 %lineCnt%) do (
set "ln="
set /p "ln="
set "var=!var!!ln!!lf!"
)
)
set var

Resources