Read words separated by space in a batch script - batch-file

I need to read the content of a text file word by word, in a batch script. The words are space separated. I tried this but it doesn't work, it only takes the first word:
for /f "delims= " %%i in (%OUTPUT_FILE%) do echo %%i
I also tried this but doesn't work also:
for /f "tokens=* delims= " %%i in (%OUTPUT_FILE%) do echo %%i

for /f "delims=" %%a in (file.txt) do for %%b in (%%a) do echo %%b
Delimiters: space, tab, 0xFF, , ; =.

Here is a pure batch solution that should be able to handle any content in your file. It reads each line with an outer FOR /F, and replaces each space with a newline character. It reads each resulting line (word) with an inner FOR /F.
#echo off
setlocal disableDelayedExpansion
:: Define LF to contain a newline character
set LF=^
:: Above 2 blank lines are critical - DO NOT REMOVE
for /f "eol= tokens=*" %%A in (%OUTPUT_FILE%) do (
set "ln=%%A"
setlocal enableDelayedExpansion
for %%L in ("!LF!") do for /f "eol= " %%W in ("!ln: =%%~L!") do echo(%%W
endlocal
)
Life is much simpler if you use a hybrid JScript/batch utility called REPL.BAT that performs regex search and replace on stdin and writes the result to stdout.
Assuming REPL.BAT is in your current folder, or better yet, somewhere within your PATH:
for /f "eol= " %%W in ('repl " " "\n" x ^<%OUTPUT_FILE%') do echo(%%W

Tokens control the elements split from delimiters that are available. So depending on what your overall goal is, it might be worth pursuing tokens to retrieve the desired variables. If you know how many elements will be on each line of your text file, such as a config file or key value pairs on each line, you could leverage 'tokens=' to get what you need.
for /f "tokens=1,2 delims= " %%a in (%OUTPUT_FILE) do echo %%a %%b
If the items per line is unknown, Endoro's word loop inside the line loop is definitely the way to go.

Related

Replace characters in filename through .bat

I have a file named - for example: 01_XXXXXXXX_XXXX_XXX.txt.
I need to strip out the first three characters (replace 01_ by nothing) and replace the remaining _ by SPACEs.
I cannot use PowerShell, I do need to have a simple .batfile, to loop through all files in the directory where it is present, and do this task.
So I am using this:
#echo off
setlocal enabledelayedexpansion
for %%a in (*_*) do (
set file=%%a
ren "!file!" "!file:_= !"
)
#echo off
setlocal enabledelayedexpansion
set X=2
for %%f in (*) do if %%f neq %~nx0 (
set "filename=%%~nf"
set "filename=!filename:~%X%,-%X%!"
ren "%%f" "!filename!%%~xf"
)
popd
But it is eating two characters at the end before the extension and adding a SPACE at the beginning.
Any idea why?
You are splitting off the first two and the last two characters, as you implemented the sub-string expansion syntax wrongly. The leading SPACE derives from the first _ before the replacements.
The following shows a reliable way of doing it, using a single loop and sub-string replacement syntax only, the first time with the * immediately after the :, telling the command line interpreter to replace everything up to and including the first occurrence of the search string:
#echo off
setlocal EnableExtensions DisableDelayedExpansion
for %%A in ("*_*") do (
rem // Store current item:
set "FILE=%%~A"
rem // Toggle delayed expansion to avoid loss of or trouble with `!`:
setlocal EnableDelayedExpansion
rem // Remove everything up to and including the first `_`:
set "FNEW=!FILE:*_=!"
rem // Replace every remaining `_` by ` `:
ren "!FILE!" "!FNEW:_= !"
endlocal
)
endlocal
exit /B
If your pattern is consistent with 01_XXXXXXXX_XXXX_XXX.txt (i.e. an unrequired string ending with _ followed by three required strings separated by _), then a one liner like this may suffice:
From a batch file:
#For /F "Tokens=1-4 Delims=_" %%A In ('Where ?*_?*_?*_?*.txt') Do #If Not Exist "%%B %%C %%D" #Ren "%%A_%%B_%%C_%%D" "%%B %%C %%D"
From the command prompt:
For /F "Tokens=1-4 Delims=_" %A In ('Where ?*_?*_?*_?*.txt') Do #If Not Exist "%B %C %D" #Ren "%A_%B_%C_%D" "%B %C %D"

How to seprate space and more than one space delimiter in a batch For loop?

I have a problem to parse a text as a result of "net user" command
ABC ABCDE ABCDEFG
ABDCS HFJ ATi CObdnsen
to single users in a separate lines in batch script.
my code is this :
FOR /F "tokens=1,2,3 delims= " %%A in (test.txt) do echo %%A & echo %%B & echo %%C
the problem is the second line of my text that contains a username with space in the middle.
Note that i want this result :
ABC
ABCDE
ABCDEFG
ABDCS HFJ
ATi
CObdnsen
so what is the solution?
That looks to be fixed width columns, 25 characters per column. You could load each line into a variable and use substring operations to get the values.
#echo off
setlocal enableDelayedExpansion
for /f delims^=^ eol^= %%A in (test.txt) do (
set "ln=%%A"
echo col1=[!ln:~0,25!]
echo col2=[!ln:~25,25!]
echo col3=[!ln:~50!]
echo(
)
But that leaves you with the problem of removing trailing spaces from the end of each value. It is doable, but not easy with batch. My output from the above script encloses the values within square brackets so you can easily see the trailing space issue.
Instead of messing with the issue of removing trailing spaces, I would use my REPL.BAT utility to transform the data from fixed width to delimited format. REPL.BAT is a hybrid JScript/batch utility that performs a regular expression search/replace operation on stdin and writes the result to stdout. It is pure script that will run on any modern Windows machine from XP onward without needing any 3rd party executables. Full documentation is embedded within the script.
I would use REPL.BAT to insert a delimiter after the 25th and 50th characters. I would then use another REPL.BAT to strip out any spaces that precede the delimiter, and then a normal FOR /F can safely parse the values. I chose to use a pipe (|) as the delimiter.
#echo off
for /f "eol=| delims=| tokens=1-3" %%A in (
'type test.txt ^| repl "^(.{25})(.{25})" "$1|$2|" ^| repl " *\|" "|"'
) do (
echo col1=[%%A]
echo col2=[%%B]
echo col3=[%%C]
echo(
)
If you know that no value contains consecutive spaces, and all values are separated by at least 2 spaces, then you can get by with a single REPL that replaces 2 or more spaces with a delimiter
#echo off
for /f "eol=| delims=| tokens=1-3" %%A in (
'type test.txt ^| repl " {2,}" "|"'
) do (
echo col1=[%%A]
echo col2=[%%B]
echo col3=[%%C]
echo(
)
#echo off
setlocal enableextensions
for /f "tokens=*" %%a in ('net user^|find " "') do (
set "u=%%a"
setlocal enabledelayedexpansion
set "u=!u: =/!"
set "u=!u:/ =/!"
for /f "tokens=1 delims=/" %%b in ("!u!") do echo %%b
endlocal
)
endlocal
Not bullet proof. Will fail for user names with two spaces in it or (probably, not tested) with names of 24 characters or more (just to name two).
Thanks MC ND for your great idea... But your Answer should be edited like below for the best result :
#echo off
setlocal enableextensions
for /f "tokens=*" %%a in ('net user^|find " "') do (
set "u=%%a"
setlocal enabledelayedexpansion
set "u=!u: =/!"
set "u=!u:/ =/!"
for /f "tokens=1,2,3 delims=/" %%b in ("!u!") do echo %%b & echo %%c & echo %%d
endlocal
)
endlocal
Note that the delimiter is "5 spaces". because the most allowed user length is 20 character in windows. and the distance between the columns are 25 character.. so we have at least 5 spaces as a good delimiter. and we are not worry about spaces in the middle of a username.
and at last your should parse three tokens . Not only 1 token.
Thanks for your attention guys.

Tokenize strings in a batch file

Suppose I have a file, and I don't know how many words there are in it. I would like to go through this file and echo every word, one at a time. Is there a way to do that? The delim is space and I don't know how many words I will be going through because the file content may change.
For example, if the file contains:
"Hello world
I hope winter should be over soon"
Then I would like the output to be:
"Hello
world
I
hope
winter
should
be
over
soon"
Thanks in advance!
Here is how to do it in batch. I picked this up here awhile back but I don't remember who wrote it. Probably Jeb or dbenham. It looks like their code ;)
#echo off
setlocal disableDelayedExpansion
:: Define LF to contain a newline character
set LF=^
:: Above 2 blank lines are critical - DO NOT REMOVE
for /f "eol= tokens=*" %%A in (hw.txt) do (
set "ln=%%A"
setlocal enableDelayedExpansion
for %%L in ("!LF!") do (
for /f "eol= " %%W in ("!ln: =%%~L!") do echo %%W
)
endlocal
)
The following will work, unless there are double quotes in the text.txt file. Are you sure you are going to have double quotes in your text file? If you don't care about the double quotes, this can be further tuned to strip out the quotes before splitting it
#ECHO OFF
:: Read file text.txt line by line
FOR /F "tokens=* delims=" %%X IN (text.txt) DO (
CALL :SPLIT %%X
)
EXIT /B 0
:SPLIT
:: Verify parameter is not blank, else quit
IF ["%*"]==[""] EXIT /B 0
:: Extract first token, recursively :SPLIT the remainder
FOR /F "tokens=1,* delims= " %%A IN ("%*") DO (
ECHO %%A
CALL :SPLIT %%B
)
The first FOR loop will read the text.txt file, line by line.
The :SPLIT recursive function will take a line, and split it by delimiter of space until there is nothing left in the line.
This uses a helper batch file called repl.bat - download from: https://www.dropbox.com/s/qidqwztmetbvklt/repl.bat
Place repl.bat in the same folder as the batch file or in a folder that is on the path.
type "file.txt"|repl " " "\r\n" x

Using Wildcard in Set command in batch file

ok I am trying to strip the first two characters from a file I am using this script.
#echo off
Set "InputFile=C:\New Folder\test.txt"
Set "OutputFile=C:\New Folder\New\test.txt"
setLocal EnableDelayedExpansion > "%OutputFile%"
for /f "usebackq tokens=* delims= " %%a in ("%InputFile%") do (
set s=%%a
>> "%OutputFile%" echo.!s:~2!
)
which works perfect if I use the correct name. What I need to do is use a wild characters since the name of the file is different each time. When trying this it does not work.
#echo off
Set "InputFile=C:\New Folder\H*.txt"
Set "OutputFile=C:\New Folder\New\H*.txt"
setLocal EnableDelayedExpansion > "%OutputFile%"
for /f "usebackq tokens=* delims= " %%a in ("%InputFile%") do (
set s=%%a
>> "%OutputFile%" echo.!s:~2!
)
from
I'd like to use a wildcard with the SET command in Windows Batch so I don't have to know exactly what is in the string in order to match it
The asterisk IS a wildcard and WILL match multiple characters, but
will ONLY match everything from the very beginning of the string. Not
in the middle, and not from the end.
Useful Searches:
*x
*how are you? The above two searches CAN be matched. The first will match everything up to and including the first "x " it runs across.
The second one will match everything up to and including the first
"how are you?" it finds.
Legal, but Unuseful, searches:
x* Hello* OneThree The above three searches can NEVER be matched.
Oddly they are also legal, and will cause no errors. One exception:
Hello and x* WILL match themselves, but only if they are the very
beginning of the string. (Thanks Jeb!)
the surrounding for-loop does the wildcard processing (giving full qualified filenames)
#echo off
for /f %%i in ('dir /b C:\New Folder\H*.*') do (
echo processing %%i
Set "InputFile=C:\New Folder\%%i"
Set "OutputFile=C:\New Folder\New\%%i"
setLocal EnableDelayedExpansion > "%OutputFile%"
for /f "usebackq tokens=* delims= " %%a in ("%InputFile%") do (
set s=%%a
>> "%OutputFile%" echo.!s:~2!
)
endlocal
)
Note: if you have more than one line in those files, it will remove the first two characters from each line*.

How to loop through tokens in a string?

Say I have a string such as foo:bar:baz, is it possible to loop through this string? It looked like you could tokenize lines of a file but the following will only echo 'foo' once.
for /f "tokens=1,2* delims=:" %%x in ("%%j") do echo %%x
set string=foo:bar:baz
for %%x in (%string::= %) do echo %%x
FOR value delimiters may be space, comma, semicolon and equal-sign. You may directly process a string if the elements are delimited with any of these characters. If not, just change the delimiter for one of these character (as I did above).
set string=foo bar,baz;one=two
for %%x in (%string%) do echo %%x
Aacini beat me to my first solution. It can be improved by adding quotes so that the string can contain spaces and special characters and still give the correct result.
set "str=foo bar:biz bang:this & that"
for %%S in ("%str::=" "%") do echo %%~S
The solution has limitations:
No * or ? can appear in the string
Problems can arise if the string already contains quotes ("), especially if there are special characters as well
The second solution has bizarre syntax, but the concept is fairly straight forward. FOR /F with "string" will break on linefeed characters - each line will be processesed as its own string. The trick is to replace the : delimiter with a linefeed character. Note that the blank line in the solution below is a critical part of the tricky replacement. Also, the following line must start with the ! which terminates the delayed variable expansion. There should not be any leading spaces.
The other thing to worry about is the pesky FOR /F "EOL" option. We don't want to skip any values that start with the EOL character which is ; by default. Since we have eliminated the string delimiter :, we can safely use that as the EOL.
Finally, we need to use delayed expansion, but ! will be corrupted during %%S expansion if we don't first disable delayed expansion within the loop.
set "str=foo bar:biz bang:this & that "^& the other thing!":;How does this work?"
setlocal enableDelayedExpansion
set ^"str=!str::=^
!"
for /f "eol=: delims=" %%S in ("!str!") do (
if "!!"=="" endlocal
echo %%S
)
I believe this technique can handle just about anything you throw at it.
jeb was the first to show me how to work with line feeds within batch, and especially how to use this technique. It may even be posted already somewhere else on SO.
it does as expected, it tokenizes it to %%x %%y %%z. So instead of just processing %%x, you might...
for /f "tokens=* delims=:" %%x in ("foo:bar:baz") do (
echo %%x
echo %%y
echo %%z
)
or if you don't know in advance how many items you got, you may...
#echo off
set string=foo:bar:baz
:again
for /f "tokens=1* delims=:" %%x in ("%string%") do (
echo %%x
set string=%%y
)
if not .%string%==. goto again
echo done
This will parse the string into variables accessable outside of the loop (;
setlocal enabledelayedexpansion
set your_string="whatever:you:want"
for /f "tokens=1,2,3 delims=:" %%a in ('echo !your_string!') do (
set first_sub_string=%%a
set second_sub_string=%%b
set third_sub_string=%%c
)
echo Congrats. !your_string! was parsed as !first_sub_string!, !second_sub_string!, !third_sub_string!

Resources