In batch split a string to new lines in file by delimiter - batch-file

In batch I'm trying to split a string into substrings preferably based on a delimiter.
This example works but is there a better way to do this:
for /f "tokens=1-20 delims=:" %%a in (string.txt) do (
echo %%a& echo.%%b& echo.%%c& echo.%%d& echo.%%e& echo.%%f& echo.%%g& echo.%%h& echo.%%i& echo.%%j
echo.%%k& echo.%%l& echo.%%m& echo.%%n& echo.%%o& echo.%%p& echo.%%q& echo.%%r& echo.%%s& echo.%%t
) >substrings.txt
I have tried this code from Magoo which works for default delimiters but fails using colon:
#echo off
setLocal
for /f "delims=:" %%a in (string.txt) do (
for %%i in (%%a) do echo %%i >>substrings.txt
)
I have also tried this code from Aacini but it seems to fail using special characters.
#echo off
setlocal EnableDelayedExpansion
set i=1
set "x=%string%"
set "x!i!=%x::=" & set /A i+=1 & set "x!i!=%"
set x >substrings.txt
An example %string% var or string.txt is:
Select project:/option:report name="Sustainability":option value="201":Huonville:/option:/report:report name="Energy and Water Management":option value="102":Cygnet:/option:/report:report name="Tree Management":option value="101":Cygnet:/option:/report:option disabled="disabled":/option:/select
I am trying to output %string% var or string.txt to substring.txt as follows:
Select project
/option
report name="Sustainability"
option value="201"
Huonville
/option
/report
report name="Energy and Water Management"
option value="102"
Cygnet
/option
/report
report name="Tree Management"
option value="101"
Cygnet
/option
/report
option disabled="disabled"
/option
/select
Any help would be greatly appreciated. Thanks

When you use for /f, you need to know how many tokens there are (and there is a limit for max tokens).
You need a plain for loop, but you can't choose, which delimiter should be used.
So replace every delimiter with a space. Be sure to have quotes around each "token" to take care of original spaces. To do this, put quotes around the whole string and replace the delimter : with " ":
#echo off
setlocal enabledelayedexpansion
set "string=Select project:/option:report name="Sustainability":option value="201":Huonville:/option:/report:report name="Energy and Water Management":option value="102":Cygnet:/option:/report:report name="Tree Management":option value="101":Cygnet:/option:/report:option disabled="disabled":/option:/select""
set "string=%string: =#%"
set "string="%string::=" "%"
(for %%a in (%string%) do (
set "out=%%~a"
echo !out:#= !
))>out.txt
echo take a look at the modified string:
echo %string%
echo/
type out.txt
Another approach (just for academic reasons):
#echo off
setlocal
set "string=Select project:/option:report name="Sustainability":option value="201":Huonville:/option:/report:report name="Energy and Water Management":option value="102":Cygnet:/option:/report:report name="Tree Management":option value="101":Cygnet:/option:/report:option disabled="disabled":/option:/select"
call :recur %string%
goto :eof
:recur
rem echo loop with %*
for /f "tokens=1,* delims=:" %%a in ("%*") do (
echo %%a
if not "%%~b" == "" call :recur %%b
goto :eof
)
echo.
Note: there is a recursion limit (due to stack-size). It works with the given string, but may fail when the string contains more "tokens".

See #dbenham's AMAZING CERTUTIL string replacement technique. It works for any characters, even exclams!
#echo off
====SETLOCAL EnableDelayedExpansion EnableExtensions
set "B=^!"
set "C=^"
set ^"L=^
%===Line Feed===%
"
for /F "eol=N" %%C in ('wmic os get Name /value') do set "R=%%C" Carriage Return
set ^"E=!R!!L!" CRLF
>nul 2>&1 certutil -f -encodehex String.txt "%temp%\hex.txt" 4
pushd "%temp%"
>expand.txt (FOR /F "delims=" %%A in (hex.txt) do FOR %%B in (%%A) do (
set "char=%%B"
REM ! --> !B! ###
set "char=!char:21=21 42 21!"
REM ^ --> !C! ###
set "char=!char:5e=21 43 21!"
REM <CR> --> !R! ###
set "char=!char:0a=21 4c 21!"
REM <LF> --> !L! ###
set "char=!char:0d=21 52 21!"
REM : --> !R!!L! ###
set "char=!char:3a=21 45 21!"
echo(!char!
))
>nul 2>&1 certutil -f -decodehex expand.txt rawContent.txt
for /f delims^=^ eol^= %%A in (rawContent.txt) do set "modified=%%A"
del hex.txt expand.txt rawContent.txt
popd
>substring.txt (
echo(!modified!
)

This is a summary of what Stephan came up with.
#echo off
setlocal enabledelayedexpansion
set /p string=<"input.txt"
set "string=%string: =#%"
set "string="%string::=" "%"
(for %%a in (%string%) do (
set "output=%%~a"
echo !output:#= !
))>output.txt
Set string or input text file (modify line 3).
set /p string=<"input.txt"
The delimiter in this example is colon [:] which follows after [string:] (modify line 5).
set "string="%string::=" "%"
If string or input.txt contains quotes %string% may need to be double quoted (modify line 3).
for /f "delims=" %%a in (input.txt) do (set string="%%a")
#echo off
setlocal enabledelayedexpansion
for /f "delims=" %%a in (input.txt) do (set string="%%a")
set "string=%string: =#%"
set "string="%string::=" "%"
(for %%a in (%string%) do (
set "output=%%~a"
echo !output:#= !
))>output.txt

Related

How to read all content from text flie in single variable in Batch Script?

This is my first experience in batch script, i am trying to read text file content and trying to set its content in single variable i am using .bat file to run script but script not working.
i want to set all content of file in single variable.
tried most of example but failure.
below is my script which i am trying
cd "C:\documents and settings\%USERNAME%\desktop"
for /f "delims=" %%x in (Test.txt) do set Build=%%x
pause >nul
exit
This is my Text File
And
below result is showing
i want it in single variable
cd "C:\documents and settings\%USERNAME%\desktop"
setlocal enableDelayedExpansion
for /f "useback delims=" %%x in ("Test.txt") do set "Build=!build! %%x"
echo %build%
pause >nul
exit
Mind that the max length of a string you can assign to a variable is 8191 symbols.
Also some special symbols could break the script above (%,! ..)
i want to set all content of file in single variable.
In batch, the only way is to construct a multi-line variable yourself, named !LF!
#echo off
SETLOCAL EnableDelayedExpansion
::Change this
set "file=%~f0"
if NOT EXIST "%file%" exit /b 1
::Initialize & empty variables
( set LF=^
%= 0x0D Form Feed =%
)
set "lines="
set "data="
::Count lines
FOR /F tokens^=*^ delims^=^ eol^= %%L in (
'2^>nul findstr /N "^" "%file%"'
) do set /a "lines+=1"
::Read file using SET /P
<"%file%" (
for /L %%a in (1 1 %lines%) do (
set "x=" %= Workaround for empty lines =%
set /p "x="
set "data=!data!!LF!!x!"
)
)
::Print data
echo(!data!
ENDLOCAL
pause & exit /b
The FOR /F tokens^=*^ delims^=^ eol^= disables eol by escaping every delimiter. Warning: "eol=" DOES NOT disable eol, but sets the quote " as the end-of-line character!
Disadvantages:
SLOW: On my machine, it takes 2 seconds for a 2000 lines file, printing the variable excluded
The line ending style (\n or \r\n is ignored, and always set to \n)
Additional \n at the beginning of variable
Advantages:
SAFE: Always works for any file with printable ASCII characters (0x20 ~ 0x7E)
You can also use #dbenham's CERTUTIL method. It is foolproof against <CR> <LF> ! ^...
See more tricks with certutil for the "poorly documented" switches explained in depth.
#echo off
====SETLOCAL EnableDelayedExpansion EnableExtensions
set "B=^!"
set "C=^"
set ^"L=^
%===Line Feed===%
"
for /F %%C in ('wmic qfe list') do set "R=%%C" Carriage Return
>nul 2>&1 certutil -f -encodehex Test.txt "%temp%\hex.txt" 4
pushd "%temp%"
>expand.txt (
for /f "delims=" %%A in (hex.txt) do for %%B in (%%A) do (
set "char=%%B"
REM ! --> !B!
set "char=!char:21=21 42 21!"
REM ^ --> !C!
set "char=!char:5e=21 43 21!"
REM <CR> --> !R!
set "char=!char:0a=21 4c 21!"
REM <LF> --> !L!
set "char=!char:0d=21 52 21!"
echo(!char!
)
)
>nul 2>&1 certutil -f -decodehex expand.txt rawContent.txt
for /f delims^=^ eol^= %%A in (rawContent.txt) do set "fileContent=%%A"
del hex.txt expand.txt rawContent.txt
popd
echo(!fileContent!

rename a file removing part of the filename batch script

I have some files in the form:
filename1 1 extra1.ext
filename1 2.ext
filename1 3 extra2.ext
...
filename2 1.ext
filename2 100 extra3.ext
...
filename20 1.ext
filename20 15 extra100.ext
(etc.)
...where filename1, filename2, etc., can contain spaces, symbol ' but not numbers. And extra1, extra2, etc, can contain anything. The number in the file name enclosed by spaces does not repeat per same filename1, filename2, etc.
What i want is to remove the extra things of the files that contain it. That is, to get from filename20 15 extra100.ext to filename20 15.ext
My first attempt is this:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "FILE=file name 11 con sosas extras 2.txt"
set "ext=txt"
set "folder=."
for /F "tokens=1,* delims=0123456789" %%A in ("!FILE!") do (set "EXTRA=%%B")
set "FIRST=!FILE:%EXTRA%=!"
set "filename=!FIRST!.!ext!"
echo !EXTRA!
echo !filename!
echo rename "!folder!\!FILE!" "!filename!"
that seems to work, but if i change it to receive parameters, it doesn't:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "FILE=%1"
set "ext=%2"
set "folder=%3"
for /F "tokens=1,* delims=0123456789" %%A in ("!FILE!") do (set "EXTRA=%%B")
set "FIRST=!FILE:%EXTRA%=!"
set "filename=!FIRST!.!ext!"
echo !EXTRA!
echo !filename!
echo rename "!folder!\!FILE!" "!filename!"
where %1 is the filename, %2 is the extension and %3 is the folder in which the files are. Probably, the extension can be extracted inside the batch, but i don't know how to do it.
On another hand, i plan to use this batch into another one. There, there will be a for loop in (*.txt) and i don't know how to differentiate between files that have extra things (and then call this batch) from files that doesn't (and then not call this batch).
Regards,
use your method to extract the "extra-portion". In a second step, remove that extra-portion:
#echo off
setlocal enabledelayedexpansion
set "FILE=file name 11 con sosas extras 2.txt"
for /f "tokens=1,* delims=1234567890" %%a in ("%file%") do set new=!file:%%b=!%%~xb
echo %new%
%%~xb gives you the extension.
Here is a batch script that seeks the first purely numeric string portion enclosed within SPACEs, or in case it appears at the end, preceded by a SPACE, that occurs after some other text not consisting of SPACEs only. The part in front of the found number followed by a SPACE followed by the number itself are used for building the new file name.
This approach handles all valid characters for file names properly, even ^, &, %, !, ( and ).
So here is the code:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_SOURCE=.\test"
for /F "eol=| delims=" %%F in ('
dir /B "%_SOURCE%\*.ext" ^| findstr /R /I ^
/C:"^..* [0123456789][0123456789]*\.ext$" ^
/C:"^..* [0123456789][0123456789]* .*\.ext$"
') do (
set "FILE=%%F"
call :SPLIT FIRST NUM REST "%%~nF"
if defined NUM (
setlocal EnableDelayedExpansion
ECHO rename "!_SOURCE!\!FILE!" "!FIRST! !NUM!%%~xF"
endlocal
)
)
endlocal
exit /B
:SPLIT rtn_first rtn_num rtn_rest val_string
setlocal DisableDelayedExpansion
set "RMD=" & set "NUM=" & set "STR=%~4"
:LOOP
for /F "tokens=1,2,* delims= " %%I in ("%STR%") do (
if not "%%J"=="" (
(for /F "delims=0123456789" %%L in ("%%J") do rem/) && (
if not "%%K"=="" (
set "STR=%%J %%K"
goto :LOOP
)
) || (
set "NUM=%%J"
if not "%%K"=="" (
set "RMD=%%K"
)
)
)
)
set "STR=%~4"
if not defined NUM goto :QUIT
set "STR=%STR% "
call set "STR=%%STR: %NUM% =|%%"
for /F "delims=|" %%L in ("%STR:^^=^%") do set "STR=%%L"
:QUIT
(
endlocal
set "%~1=%STR%"
set "%~2=%NUM%"
set "%~3=%RMD%"
)
exit /B
After having tested the script, remove the upper-case ECHO command to actually rename any files.

Batch Files: How to concatenate each line in a text file?

I have a text file with text on each line. I would like to be able to put each line in one long line along with a space. So, if the text file has:
Bob
Jack
Sam
I want the result to be
Bob Jack Sam
Below are two methods that I am working on but I am stuck. Anything in brackets [] means that I know the syntax is completely wrong; I only put it there to show my thought process. The commented sections are just me experimenting and I have left them in case anyone wants to comment on what they would do / why they do what they do.
Method 1:
#echo off
SETLOCAL EnableDelayedExpansion
SET count=1
FOR /F "tokens=* delims= usebackq" %%x IN ("afile.txt") DO (
SET var!count!=%%x
for %%a in (!count!) do (
!var%%a! = !var%%a! & " "
echo !var%%a!
)
SET /a count=!count!+1
echo !count!
)
::echo !var1! !var2! !var3!
start "" firefox.exe !var%%a!-1
ENDLOCAL
::echo "endlocal" %var1% %var2% %var3%
Method 2:
#echo off
SETLOCAL EnableDelayedExpansion
SET count=1
FOR /F "tokens=* delims= usebackq" %%x IN ("afile.txt") DO (
SET var!count!=%%x
call echo %%var!count!%%
SET /a count=!count!+1
echo !count!
)
::echo !var1! !var2! !var3!
start "" firefox.exe ^
[i = 1]
[for i to !count! do (]
call echo %%var!count!%% & " " & " "^
ENDLOCAL
::echo "endlocal" %var1% %var2% %var3%
If you only have three values, you can directly retrieve them from the file
< input.txt (
set /p "line1="
set /p "line2="
set /p "line3="
)
set "var=%line1% %line2% %line3%"
echo("%var%"
If you don't know the number of values, use a for /f command to read the lines and concatenate the contents into a variable.
#echo off
setlocal enableextensions enabledelayedexpansion
set "var="
for /f "usebackq delims=" %%a in ("input.txt") do set "var=!var!%%a "
echo("%var%"
But if the data can contain exclamation signs, the delayed expansion state will remove them (and the text surounded by them). To avoid it, this can be used
#echo off
setlocal enableextensions disabledelayedexpansion
set "var="
for /f "usebackq delims=" %%a in ("input.txt") do (
setlocal enabledelayedexpansion
for /f "tokens=* delims=¬" %%b in ("¬!var!") do endlocal & set "var=%%b%%a "
)
echo("%var%"
where the setlocal/endlocal and the inner for are used to avoid problems with ! character
Or you can try something like this
#echo off
setlocal enableextensions disabledelayedexpansion
for /f "delims=" %%a in ('
"<nul cmd /q /c "for /f "usebackq delims=" %%z in ("input.txt"^) do (set /p ".=%%z "^)""
') do set "var=%%a"
echo("%var%"
It runs a cmd instance to output the input lines as only one output line (<nul set /p is used to ouput the data without line feeds, so all data is in the same line). This is wrapped in a for to retrieve the output inside a variable
Would this work for you?
#echo off
SET var=
SETLOCAL EnableDelayedExpansion
FOR /f %%i in (afile.txt) DO (
SET var=!var!%%i
)
echo !var!
ENDLOCAL
Notice there is a space after the SET var=!var!%%i[Space Here] to separate each word in each row
EDIT:
If you want to display the current value in the loop just print %%i with NO concatenation. After the FOR loop finishes it will print the last value assigned to the variable
#echo off
SET var=
SETLOCAL EnableDelayedExpansion
for /f %%i in (input.txt) do (
SET var=%%i
echo !var!
)
echo %var%
Will print:
Bob
Jack
Sam
Sam
Try this: Post Edited.
#Echo off
Set "File=Recent_Log.txt"
Set "Output=My_Log.txt"
(
For /F %%F in (%File%) Do (
Set /p ".=%%~F "
)
) > "%Output%" < Nul
Goto :Eof
Because this is the first link after a Google search, I post my solution(Windows 7/10 .bat):
for %%f in (h:\blaba\*.*) do (type "%%f" & echo.) >> h:\sfsdf\dd.txt
NOTE: When your directory/filename contains spaces use double quotes.

Batch macro displaying date and time followed by text

What I have done so far (displays both date and time on a WIN2K3 5.2.3790 machine with a leading space) :
SET DATETIME=(FOR /F %%C IN ('TIME/T') DO SET /P NOW=%%C : )&(FOR /F "TOKENS=2 DELIMS= " %%A IN ('DATE/T') DO SET /P NOW=%NOW% %%A <NUL)
%DATETIME%
I want to remove the leading space before the date that the set /p adds and add parameter for text but can't find a solution. I would also like to add a parameter for text as described here http://ss64.com/nt/syntax-macros.html once the set /p gets solved.
What I would like to get as a result (but with a batch macro instead of a call) :
#ECHO OFF
CALL :DATETIME "HELLO WORLD "
PAUSE>NUL
:DATETIME
FOR /F "TOKENS=*" %%A IN ('DATE/T') DO FOR %%B IN (%%A) DO SET NOW=%%B
FOR /F %%C IN ('TIME/T') DO SET /P NOW=%NOW% %%C %~1< NUL
Thank you,
I get the impression that the task is to echo a date and time and text on the same line:
echo %date% # %time% - "Hello World"
As you referenced the macros at ss64.com you should try to use the syntax shown there.
It's not necessary but a good way to use the %\n% formatting.
#ECHO OFF
set LF=^
::Above 2 blank lines are required - do not remove
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"
SET DATETIME=( %\n%
FOR /F "TOKENS=*" %%A IN ('DATE/T') DO ( %\n%
FOR /F %%C IN ('TIME/T') DO SET /P "NOW=%%A%%C "^<NUL%\n%
)%\n%
)
set datet
echo ------
%DATETIME%
echo Hello World

MS-DOS batch script: assignment operation

I am referring to below threat Batch files: How to read a file?. For retrieving the line by line from a text file. I am using the below script:
#echo off
SETLOCAL DisableDelayedExpansion
FOR /F "usebackq delims=" %%a in (`"findstr /n ^^ paths.txt"`) do (
set "var=%%a"
SETLOCAL EnableDelayedExpansion
set "var=!var:*:=!"
echo !var!
ENDLOCAL
)
Code is working fine! The values in !var! can not assign to any variable. :( I struct there, Please anyone help to read line by line and I wish to assign to some variable and want to manipulate that variable. Please help to solve this situation.
Update:
#ECHO off
CLS
SET PROJ_DIR=D:\workspace\proj
SET PROMO_DIR=D:\TEST
SET SOURCE_CODE=\Source Code
SETLOCAL DisableDelayedExpansion
for /f %%a in (paths.txt) do (
SET "var=%%a"
SETLOCAL EnableDelayedExpansion
set "var=!var:*:=!"
set FILE_PATH=!var://www.domain.com/path/dir=!
SET FILE_PATH=!FILE_PATH:/=\!
SET PROMO_FILE_PATH=!PROMO_DIR!!SOURCE_CODE!!FILE_PATH!
FOR %%i IN ("!PROMO_FILE_PATH!") DO SET FOLDER_PATH=%%~dpi
FOR %%i IN ("!PROMO_FILE_PATH!") DO SET FILE_NAME=%%~nxi
IF EXIST "!FOLDER_PATH!" GOTO F3
MKDIR "!FOLDER_PATH!"
:F3
IF NOT EXIST "!PROJ_DIR!!FILE_PATH!" GOTO F4
COPY "!PROJ_DIR!!FILE_PATH!" "!FOLDER_PATH!"
:F4
ECHO Cannot find the file under "!PROJ_DIR!!FILE_PATH!"
ENDLOCAL
)
SET CLOSE_CONFIRM=
SET /P CLOSE_CONFIRM=Press any key to close the window...%=%
paths.txt
//www.domain.com/path/dir/dir1/dir2/file1.txt
//www.domain.com/path/dir/dir1/dir2/file2.txt
//www.domain.com/path/dir/dir1/dir2/file3.txt
//www.domain.com/path/dir/dir1/dir2/file4.txt
//www.domain.com/path/dir/dir1/dir3/file1.txt
Command Output
1 file(s) copied.
Cannot find the file under "D:\workspace\proj\dir1\dir2\file1.txt"
1 file(s) copied.
Cannot find the file under "D:\workspace\proj\dir1\dir2\file2.txt"
Press any key to close the window...
thanks..
The key is the delayed expansion, expand your variables inside of parenthesis always with ! not with %.
A sample that changes X with Y
#echo off
SETLOCAL DisableDelayedExpansion
FOR /F "usebackq delims=" %%a in (`"findstr /n ^^ paths.txt"`) do (
set "var=%%a"
SETLOCAL EnableDelayedExpansion
set "var=!var:*:=!"
set "myVar=!var!"
set "myVar=!myVar:X=Y!"
echo X replaced with Y =!myVar!
ENDLOCAL
)
In your updated version the goto :label stops the for-loop immediatly
Better rewrite it to IF-Blocks
IF NOT EXIST "!FOLDER_PATH!" (
MKDIR "!FOLDER_PATH!"
)
IF EXIST "!PROJ_DIR!!FILE_PATH!" (
COPY "!PROJ_DIR!!FILE_PATH!" "!FOLDER_PATH!"
) ELSE
(
ECHO Cannot find the file under "!PROJ_DIR!!FILE_PATH!"
)
The other answers here cover the tricky bits of delayed expansion in this code. I want to add that you can often avoid most delayed expansion problems by rolling the parentheses out into a subroutine.
FOR /F "usebackq delims=" %%a in (`"findstr /n ^^ paths.txt"`) do call :HandlePath %%a
goto :eof
================
:HandlePath
set "var=%*"
set "var=%var:*:=%"
echo %var%
goto :eof
I find this code easier to maintain because each line is parsed an executed exactly when you would expect.
If you want to read each line and manipulate it:
SETLOCAL EnableDelayedExpansion
FOR /F "tokens=*" %%a IN (paths.txt) DO (
set var=%%a
ECHO %var%
PAUSE
)
ENDLOCAL
If you are trying to search a string from a file and manipulate it:
SETLOCAL EnableDelayedExpansion
FOR /F "tokens=* usebackq" %%a IN (`FIND /I 'string to search for' "C:\folder\paths.txt"`) DO (
set var=%%a
ECHO %var%
PAUSE
)
ENDLOCAL
If you are trying to search a string and manipulate each word in the string:
SETLOCAL EnableDelayedExpansion
FOR /F "usebackq tokens=1-999 delims= " %%a IN (`FIND /I 'string to search for' "C:\folder\paths.txt"`) DO (
REM %%a = first word %%b = second word etc. through the alphabet
set var1=%%a%%b%%c
set var2=%%d
ser var3=%%e
ECHO %var1% %var2% %var3%
PAUSE
)
ENDLOCAL
This works for me:
#echo off
SETLOCAL EnableDelayedExpansion
FOR /F "usebackq delims=" %%a in (`"findstr /n ^^ paths.txt"`) do (
set var=%%a
set var=!var:*:=!
echo !var!
)
ENDLOCAL

Resources