Windows Batch File: Loop on rows and split string - windows

I have a text file with the following format:
name1:surname1
name2:surname2
name3:surname3
and so on.
I need to write a for loop in window batch script and assign to 2 variables
name=name1
surname=surname1
and so on. Something like (this is wrong)
for /F "tokens=*" %%row in (myfile.txt) do (
for /F "tokens=1* delims=:" %%u in ("%row%") do (
....
)
)
Any suggest?

You don't really need two nested loops for that.
What you probably will need, however, is delayed variable expansion.
#echo off
setlocal enabledelayedexpansion
for /f "tokens=1,2 delims=:" %%u in (myfile.txt) do (
set "name=%%u"
set "surname=%%v"
echo !surname!, !name!
)
outputs this for me:
surname1, name1
surname2, name2
surname3, name3
Delayed variable expansion is what allows you to assign the single-letter loop variables (u and v in this case) to real variables and use them in the rest of the loop, by accessing them with ! instead of %.

for /F "tokens=*" %%r in (myfile.txt) do (
for /F "tokens=1* delims=:" %%u in ("%%r") do (
....
)
)
or
for /F "tokens=1* delims=:" %%u in (myfile.txt) do (
....
)
Metavariables live r and u are limited to a single (case-sensitive) alphabetical character.

#echo off
setlocal EnableDelayedExpansion
for /F "tokens=1,2 delims=:" %%u in (myfile.txt) do (
set name=%%u
set surname=%%v
echo name=!name!
echo surname=!surname!
)
output:
name=name1
surname=surname1
name=name2
surname=surname2
name=name3
surname=surname3

Related

How to use Windows batch for bicirculation

two files 1.txt 2.txt
1.txt
a2441
b4321
p8763
2.txt
Apple
banana
peach
I want to generated content in 12.bat
ren a2441 Apple
ren b4321 banana
ren p8763 peach
I try to write like this but failed
#echo on
for /f %%a in (1.txt) do (
for /f %%b in (2.txt ) do (
ren %%a %%b>>12.bat
)
)
pause
How can I achieve my desired results? help me,thks
It is not so straightforward. You'll need to skip increasing amount of lines in the inner loop , but because of the FOR parsing you'll need additional subroutine call.And if there are empty lined they need to be stripped with findstr for more accurate skipping of the lines. Also skip argument in FOR does not accept 0 so also an if is needed.
#echo off
setlocal ENABLEDELAYEDEXPANSION
set /a s=0
for /f "tokens=* delims=" %%a in (1.txt) do (
call :inner !s!
echo ren %%a !second!
set /a s=s+1
)
endlocal
pause
exit /b
:inner
set "second="
if %1==0 (
for /f "tokens=* delims=" %%b in ('findstr /r "[a-zA-Z]" "2.txt"') do (
if not defined second set "second=%%b"
)
) else (
for /f "skip=%1 tokens=* delims=" %%b in ('findstr /r "[a-zA-Z]" "2.txt"' ) do (
if not defined second set "second=%%b"
)
)
The problem with anidated loops is that for each line of the outer file/loop all the lines of the inner file/loop are processed.
One simple solution is to number the lines of both files and only generate the output line when both numbers match. Quick and dirty:
#echo off
setlocal enableextensions disabledelayedexpansion
>"12.bat" (
for /f "tokens=1,* delims=:" %%a in ('findstr /n "^" 1.txt') do (
for /f "tokens=1,* delims=:" %%c in ('findstr /n "^" 2.txt') do (
if %%a==%%c (
echo ren %%b %%d
)
))
)
This code just uses findstr to generate line numbers (/n) for each of the input files, and using the delims and tokens clauses of the for /f command to separate them from the original line contents (note: if the lines could start with a colon, more code is needed). If the line number in first file matches the line number in second file the command is echoed (there is a active output redirection to the final file)
Another option is to assign each file to a input stream and to read them using set /p operations from each of the streams
#echo off
setlocal enableextensions disabledelayedexpansion
call :processFiles 9<"1.txt" 8<"2.txt" >"12.bat"
goto :eof
:processFiles
<&9 set /p f1= || goto :eof
<&8 set /p f2= || goto :eof
echo ren %f1% %f2%
goto :processFiles
In the call to the subroutine we assign each file to a stream. Inside the subroutine each stream is read with set /p (note: set /p can not read lines longer than 1021 characters)

Groupby and count on lines of a text file in Windows CMD

I have a long files with identifiers, e.g.
A
A
B
C
A
C
I would like to do a group by, count and sort operation to get a file with:
A 3
C 2
B 1
How can I achieve it in a CMD script?
Global edit - All code has been modified to allow - in identifiers. Identifiers must not contain !
Assuming the identifiers do not contain = or $ or !, and the identifiers are NOT case sensitive, the following lists the counts sorted by identifier.
#echo off
setlocal enableDelayedExpansion
:: Clear any existing $ variables
for /f "delims==" %%V in ('set $ 2^>nul') do set "%%V="
:: Get a count of each identifier
for /f "usebackq delims=" %%A in ("test.txt") do (
set /a "cnt=!$%%A!+1"
set "$%%A=!cnt!"
)
:: Write the results to a new file
>output.txt (
for /f "tokens=1,2 delims=$=" %%A in ('set $') do echo %%A %%B
)
:: Show the result
type output.txt
The prefix can be adapted as needed. But this technique cannot be used if the identifiers are case sensitive.
EDIT
Here is a version that sorts the result by count descending
#echo off
setlocal enableDelayedExpansion
:: Clear any existing $ variables
for /f "delims==" %%V in ('set $ 2^>nul') do set "%%V="
:: Get a count of each identifier
for /f "usebackq delims=" %%A in ("test.txt") do (
set /a "cnt=!$%%A!+1"
set "$%%A=!cnt!"
)
:: Write a temp file with zero padded counts prefixed to the left.
>temp.txt (
for /f "tokens=1,2 delims=$=" %%A in ('set $') do (
set "cnt=000000000000%%B"
echo !cnt:~-12!=%%A=%%B
)
)
:: Sort and write the results to a new file
>output.txt (
for /f "tokens=2,3 delims=$=" %%A in ('sort /r temp.txt') do echo %%A %%B
)
del "temp.txt"
:: Show the result
type output.txt
EDIT 2
And here is another option sorted by count descending that assumes REPL.BAT is somewhere within your PATH
#echo off
setlocal enableDelayedExpansion
:: Clear any existing $ variables
for /f "delims==" %%V in ('set $ 2^>nul') do set "%%V="
:: Get a count of each identifier
for /f "usebackq delims=" %%A in ("test.txt") do (
set /a "cnt=!$%%A!+1"
set "$%%A=!cnt!"
)
:: Sort result by count descending and write to output file
set $|repl "\$(.*)=(.*)" "000000000000$2=$1 $2"|repl ".*(.{12}=.*)" $1|sort /r|repl ".{13}(.*)" $1 >output.txt
:: Show the result
type output.txt

Shell script hash table

I'm trying to translate a .bat file into a .sh script. Several parameters are passed to the script, one of these being a hash table. The code looks like...
date /T
time /T
FOR /F "tokens=1-11" %%A IN (%4) DO (
set args1=%%A %%B %%C %%D %%E %%F %%G %%H %%I %%J %%K
)
FOR /F "tokens=12" %%A IN ("%4") DO (
set args2=%%A
)
FOR /F "tokens=12*" %%A IN (%4) DO (
set dummy=%%A
set args3=%%B
)
I'm not sure what is going on here, or how to handle it?
Any suggestions? Or good reference pages online I can take at look at?
Here is a good reference page: http://technet.microsoft.com/en-us/library/bb490909.aspx
Breakdown
The first loop is treating the input as a filenameset.
This is storing the first 11 whitespace delimited items in the variable args1.
The second loop is treating the input as a literal string.
This is storing just the 12 whitespace delimited item in the variable args2.
The last loop is treating the input as a filenameset.
This is storing all the remaining whitespace delimited items after the 12th item in the variable args3.
Example
I would recommend adding the echo command after each loop so you can see what the parsed values look like.
FOR /F "tokens=1-11" %%A IN (%4) DO (
set args1=%%A %%B %%C %%D %%E %%F %%G %%H %%I %%J %%K
)
echo %args1%
FOR /F "tokens=12" %%A IN ("%4") DO (
set args2=%%A
)
echo %args2%
FOR /F "tokens=12,*" %%A IN (%4) DO (
set args3=%%B
)
echo %args3%

how to add space in for /f "tokens=*"

this is my myfile.txt I want to add space in second column as see the sample
ARK,LAR SNE,QNE,898,ILO,SNE,SNE,LAR,LAR,545
AUS,MNY P08,TTL,7776,STO,STL,STL,MNY,MNY,567
BOS,MTZ TNK,SDK,444,PPO,TNK,TNK,MTZ,MTZ,456
this is the code I am using
for /f "tokens=* " %%i in (myfile.txt) do call :echo2 %%i %%J %%K %%L %%M %%N %%O %%P %%Q %%R %%S
goto :EOF
:echo2
echo insert ('%1','%2','%3','%4','%5','%6','%7','%8','%9','%10'); >>myfile1.txt
goto :EOF
its displaying results , where it should have taken space what I am missing any help is appreciated
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
(
FOR /f "delims=" %%i IN (myfile.txt) DO (
SET "dataline=%%i"
SET "outline="
CALL :adddata
)
)>myfile1.txt
GOTO :EOF
:adddata
FOR /f "tokens=1*delims=," %%p IN ("%dataline%"
) DO SET outline=%outline%'%%p',&SET "dataline=%%q"
IF DEFINED dataline GOTO adddata
ECHO insert (%outline:~0,-1%);
GOTO :eof
This should do the job with no practical limit on columns - provided of course that the comma is reliably an end-of-column delimiter.
For each line in the source file, assign the entire line to
dataline and clear outline
then take the first token, delimited by comma, from dataline, quote it,add a comma and append it to outline; then set dataline to the remainder of the line after the first comma.
repeat until there is nothing left in dataline
output the text insert ( + all but the last character of outline (which will be a comma) + );
If I understand you correctly, you want to preserve the spaces in the text between the 1st and 2nd comma, correct? Try this:
#echo off
for /f "tokens=1-10 delims=," %%a in (myfile.txt) do (
>>myfile1.txt echo.insert ('%%a','%%b','%%c','%%d','%%e','%%f','%%g','%%h','%%i','%%j'^);
)
Try this:
#echo off & setlocal
(for /f "delims=" %%i in (myfile.txt) do (
set "line='%%i'"
setlocal enabledelayedexpansion
set "line=!line:,=','!"
set "line=!line: = ','!"
echo(insert (!line!^);
endlocal
))>myfile1.txt
You can't exceed 9 variables so your script won't work after the 9th. You can use for /f to copy each line exactly as the original file like so:
for /f "tokens=* " %%i in (myfile.txt) do echo %%i >>myfile1.txt
goto :EOF

Parsing string in batch file

I have the following string:
MyProject/Architecture=32bit,BuildType=Debug,OS=winpc
I would like to be able to grab the values 32bit, Debug, and winpc and store them in variables named Architecture, BuildType, and OS to reference later in the batch script. I'm normally a Unix guy so this is new territory for me. Any help would be greatly appreciated!
This should do it:
FOR /F "tokens=1-6 delims==," %%I IN ("MyProject/Architecture=32bit,BuildType=Debug,OS=winpc") DO (
ECHO I %%I, J %%J, K %%K, L %%L, M %%M, N %%N
)
REM output is: I MyProject/Architecture, J 32bit, K BuildType, L Debug, M OS, N winpc
The batch FOR loop is a pretty interesting piece of machinery. Type FOR /? in a console for a description of some of the crazy stuff it can do.
Here is an interesting solution that doesn't care how many or what order the name=value pairs are specified. The trick is to replace each comma with a linefeed character so that FOR /F will iterate each name=value pair. This should work as long as there is only one / in the string.
#echo off
setlocal enableDelayedExpansion
set "str=MyProject/Architecture=32bit,BuildType=Debug,OS=winpc"
::Eliminate the leading project info
set "str=%str:*/=%"
::Define a variable containing a LineFeed character
set LF=^
::The above 2 empty lines are critical - do not remove
::Parse and set the values
for %%A in ("!LF!") do (
for /f "eol== tokens=1* delims==" %%B in ("!str:,=%%~A!") do set "%%B=%%C"
)
::Display the values
echo Architecture=%Architecture%
echo BuildType=%BuildType%
echo OS=%OS%
With a bit more code it can selectively parse out only name=value pairs that we are interested in. It also initializes the variables to undefined in case the variable is missing from the string.
#echo off
setlocal enableDelayedExpansion
set "str=MyProject/Architecture=32bit,BuildType=Debug,OS=winpc"
::Eliminate the leading project info
set "str=%str:*/=%"
::Define a variable containing a LineFeed character
set LF=^
::The above 2 empty lines are critical - do not remove
::Define the variables we are interested in
set "vars= Architecture BuildType OS "
::Clear any existing values
for %%A in (%vars%) do set "%%A="
::Parse and conditionally set the values
for %%A in ("!LF!") do (
for /f "eol== tokens=1* delims==" %%B in ("!str:,=%%~A!") do (
if !vars: %%B ! neq !vars! set "%%B=%%C"
)
)
::Display the values
for %%A in (%vars%) do echo %%A=!%%A!
Try the following:
#ECHO OFF
SET Var=MyProject/Architecture=32bit,BuildType=Debug,OS=winpc
FOR /F "tokens=1,2,3 delims=," %%A IN ("%Var%") DO (
FOR /F "tokens=1,2 delims==" %%D IN ("%%A") DO (
SET Architecture=%%E
)
FOR /F "tokens=1,2 delims==" %%D IN ("%%B") DO (
SET BuildType=%%E
)
FOR /F "tokens=1,2 delims==" %%D IN ("%%C") DO (
SET OS=%%E
)
)
ECHO %Architecture%
ECHO %BuildType%
ECHO %OS%
PAUSE

Resources