How to use Windows batch for bicirculation - windows

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)

Related

Batch "For" loop outputs in two lines instead of one in TXT

I want this following for-loop to output the findings of these two searches in one line in the All_Metadata.txt
for %%a in (*.txt) do (
findstr /B "589" %%a
findstr /X /C:"1 1,96 " %%a
) >> All_Metadata.txt
This For-Loop output looks like this:
58998545
1 1,96
Instead of (this is what it should look like):
58998545 1 1,96
Operating System: Windows 10
Capture the output of the both findstr commands into variables with for /f loops and echo them together (no need for a variable with the second one; just use the for variable):
#echo off
setlocal ENABLEDELAYEDEXPANSION
for %%a in (*.txt) do (
set "b="
set "c="
for /f "delims=" %%b in ('findstr /B "589" "%%a"') do set "b=%%b"
for /f "delims=" %%c in ('findstr /i /X /C:"1 1,96 " "%%a"') do set "c=%%c"
echo(!b! !c!
)
Another way is, to use the set /p trick to write the first findstr result without a line feed and just add the result from the second findstr (doesn't need delayed expansion):
#echo off
setlocal
for %%a in (*.txt) do (
set "b="
for /f "delims=" %%b in ('findstr /B "589" "%%a"') do <nul set /p "=%%b "
findstr /i /X /C:"1 1,96 " "%%a"
)

How to find string and then divide the token while reading the file line by line using batch script

I have tried to do like this
Inputfile contains the file which has to be read
for /F "tokens=* delims=" %%A in (%INPUTFILE%) do (
SET my_line=%%A
SET my_line=%my_line:#define ACCEL_PRESENT%
findstr /C:"define ACCEL_PRESENT"
if %errorlevel%==0 ( SET my_line=%%A
call :parse_it
)
)
:parse_it
for /F "usebackq tokens=1-6 delims= " %%1 in ('%my_line%') do (
echo %%3 > t.txt
)
I am getting nothing from the above code.Can someone help me with the desired results
Here is one possible solution:
#echo off
setlocal EnableDelayedExpansion
for /f "tokens=* delims=" %%A in (%INPUTFILE%) do (
set "my_line=%%A"
set "my_line=!my_line:#define ACCEL_PRESENT=!"
echo !my_line! | findstr /C:"define ACCEL_PRESENT"
IF !errorlevel! EQU 0 ( SET "my_line=%%A" && call:parse_it )
)
:parse_it
for /F "usebackq tokens=1-6 delims= " %%A in ("%my_line%") do echo %%C > t.txt
rem exit /b
I hope you wanted to delete string #define ACCEL_PRESENT.
Also, say me if %my_line% is a command (I don't think so, so I removed single-quotes and I added double-quotes).
Better to use letter variables in for loops!

Batch split a text file

I have this batch file to split a txt file:
#echo off
for /f "tokens=1*delims=:" %%a in ('findstr /n "^" "PASSWORD.txt"') do for /f "delims=~" %%c in ("%%~b") do >"text%%a.txt" echo(%%c
pause
It works but it splits it line by line. How do i make it split it every 5000 lines. Thanks in advance.
Edit:
I have just tried this:
#echo off
setlocal ENABLEDELAYEDEXPANSION
REM Edit this value to change the name of the file that needs splitting. Include the extension.
SET BFN=passwordAll.txt
REM Edit this value to change the number of lines per file.
SET LPF=50000
REM Edit this value to change the name of each short file. It will be followed by a number indicating where it is in the list.
SET SFN=SplitFile
REM Do not change beyond this line.
SET SFX=%BFN:~-3%
SET /A LineNum=0
SET /A FileNum=1
For /F "delims==" %%l in (%BFN%) Do (
SET /A LineNum+=1
echo %%l >> %SFN%!FileNum!.%SFX%
if !LineNum! EQU !LPF! (
SET /A LineNum=0
SET /A FileNum+=1
)
)
endlocal
Pause
exit
But i get an error saying: Not enough storage is available to process this command
This will give you the a basic skeleton. Adapt as needed
#echo off
setlocal enableextensions disabledelayedexpansion
set "nLines=5000"
set "line=0"
for /f "usebackq delims=" %%a in ("passwords.txt") do (
set /a "file=line/%nLines%", "line+=1"
setlocal enabledelayedexpansion
for %%b in (!file!) do (
endlocal
>>"passwords_%%b.txt" echo(%%a
)
)
endlocal
EDITED
As the comments indicated, a 4.3GB file is hard to manage. for /f needs to load the full file into memory, and the buffer needed is twice this size as the file is converted to unicode in memory.
This is a fully ad hoc solution. I've not tested it over a file that high, but at least in theory it should work (unless 5000 lines needs a lot of memory, it depends of the line length)
AND, with such a file it will be SLOW
#echo off
setlocal enableextensions disabledelayedexpansion
set "line=0"
set "tempFile=%temp%\passwords.tmp"
findstr /n "^" passwords.txt > "%tempFile%"
for /f %%a in ('type passwords.txt ^| find /c /v "" ') do set /a "nFiles=%%a/5000"
for /l %%a in (0 1 %nFiles%) do (
set /a "e1=%%a*5", "e2=e1+1", "e3=e2+1", "e4=e3+1", "e5=e4+1"
setlocal enabledelayedexpansion
if %%a equ 0 (
set "e=/c:"[1-9]:" /c:"[1-9][0-9]:" /c:"[1-9][0-9][0-9]:" /c:"!e2![0-9][0-9][0-9]:" /c:"!e3![0-9][0-9][0-9]:" /c:"!e4![0-9][0-9][0-9]:" /c:"!e5![0-9][0-9][0-9]:" "
) else (
set "e=/c:"!e1![0-9][0-9][0-9]:" /c:"!e2![0-9][0-9][0-9]:" /c:"!e3![0-9][0-9][0-9]:" /c:"!e4![0-9][0-9][0-9]:" /c:"!e5![0-9][0-9][0-9]:" "
)
for /f "delims=" %%e in ("!e!") do (
endlocal & (for /f "tokens=1,* delims=:" %%b in ('findstr /r /b %%e "%tempFile%"') do #echo(%%c)>passwords_%%a.txt
)
)
del "%tempFile%" >nul 2>nul
endlocal
EDITED, again: Previous code will not correctly work for lines starting with a colon, as it has been used as a delimiter in the for command to separate line numbers from data.
For an alternative, still pure batch but still SLOW
#echo off
setlocal enableextensions disabledelayedexpansion
set "nLines=5000"
set "line=0"
for /f %%a in ('type passwords.txt^|find /c /v ""') do set "fileLines=%%a"
< "passwords.txt" (for /l %%a in (1 1 %fileLines%) do (
set /p "data="
set /a "file=line/%nLines%", "line+=1"
setlocal enabledelayedexpansion
>>"passwords_!file!.txt" echo(!data!
endlocal
))
endlocal
Test this: the input file is "file.txt" and output files are "splitfile-5000.txt" for example.
This uses a helper batch file called findrepl.bat - download from: https://www.dropbox.com/s/rfdldmcb6vwi9xc/findrepl.bat
Place findrepl.bat in the same folder as the batch file or on the path.
#echo off
:: splits file.txt into 5000 line chunks.
set chunks=5000
set /a s=1-chunks
:loop
set /a s=s+chunks
set /a e=s+chunks-1
echo %s% to %e%
call findrepl /o:%s%:%e% <"file.txt" >"splitfile-%e%.txt"
for %%b in ("splitfile-%e%.txt") do (if %%~zb EQU 0 del "splitfile-%e%.txt" & goto :done)
goto :loop
:done
pause
A limitation is the number of lines in the file and the real largest number is 2^31 - 1 where batch math tops out.
#echo off
setlocal EnableDelayedExpansion
findstr /N "^" PASSWORD.txt > temp.txt
set part=0
call :splitFile < temp.txt
del temp.txt
goto :EOF
:splitFile
set /A part+=1
(for /L %%i in (1,1,5000) do (
set "line="
set /P line=
if defined line echo(!line:*:=!
)) > text%part%.txt
if defined line goto splitFile
exit /B
If the input file has not empty lines, previous method may be modified in order to run faster.

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

Getting a list of common strings with first occurance mark

I've got bunch of text files with some content. First I wanted to number the lines globally. Then I extracted all lines that are duplicated somewhere (occur in any of given files at least twice). But now I need to mark all of these lines with the filename and line number of the first occurrence of this line. And now the funny part - it needs to be a windows batch file, using native windows tools. That's why I've got this problem to begin with.
So, to sum it up:
I have a file A with unique strings/lines, each of them is said to occur at least twice in given set of files.
I need to search these files and mark all occurrences of given line from A file with
-file name in which the line first occured
-line number in this file
This is my code with effort to number lines and format files.
#echo off
setlocal EnableDelayedExpansion
set /a lnum=0
if not [%1]==[] pushd %1
for /r %%F in (*.txt) do call :sub "%%F"
echo Total lines in %Files% files: %Total%
popd
exit /b 0
:Sub
set /a Cnt=0
for /f %%n in ('type %1') do (
set /a Cnt+=1
set /a lnum=!lnum!+1
echo ^<!lnum!^> %%n >> %1_ln.txt && echo ^<!lnum!^> >> %1_ln.txt && echo. >> %1_ln.txt
)
set /a Total+=Cnt
set /a Files+=1
echo %1: %Cnt% lines
#echo off
setlocal EnableDelayedExpansion
set lnum=0
if not "%~1" == "" pushd %1
rem "I've got bunch of text files..." (%%F is file name)
for /r %%F in (*.txt) do call :sub "%%F"
echo Total lines in %Files% files: %lnum%
popd
exit /b 0
:Sub "filename"
set Cnt=0
rem "... with some content." (%%n is line contents)
(for /f "usebackq delims=" %%n in (%1) do (
set /a Cnt+=1
rem "First I wanted to number the lines globally."
set /a lnum+=1
echo ^<!lnum!^> %%n
rem "Then I extracted all lines that are duplicated somewhere" (that were defined before)
if defined line[%%n] (
rem "I need to mark all of these lines with the filename and line number of the first occurrence of this line."
echo ^<!line[%%n]!^>
echo/
) else (
REM (Store the first occurrence of this line with *local* line number and filename)
set line[%%n]=!Cnt!: %1
)
)) > "%~PN1_ln.txt"
set /A Files+=1
echo %1: %Cnt% lines
exit /B
The above Batch program ignore empty lines in the input files and fail if they contain special Batch characters, like ! & < > |; this limitation may be fixed if required.
#ECHO OFF
SETLOCAL
FOR /f "delims=" %%s IN (A) DO (
SET searching=Y
FOR /f "delims=" %%f IN (
'dir /s /b /a-d *.txt') DO IF DEFINED searching (
FOR /f "tokens=1delims=:" %%L IN (
'findstr /b /e /n /l /c:"%%s" ^<"%%f"') DO IF DEFINED searching (
ECHO Line %%L IN "%%f" FOUND "%%s"
SET "searching="
)
)
)
Here's the meat of a routine that should do what you appear to be looking for - and that's as clear as mud.
It looks through the "A" file for each string in turn, assigns the string to %%s and sets the flag searching
Then it looks through the file list, assigning filenames to %%f
Then it executes a findstr to find the /c:"%%s" complete string %%s (including any spaces) in /l or literal mode (ie. not using regular expressions) for a line that both /b and /e begins and ends with the target (ie exactly matches) and /n numbers those lines.
The output of findstr will be in the format linenumber:linecontents so if this line is examined by the FORwith the option "delims=:" then the partion up to the first : is assigned to to %%L
So - %%L contains the line#, %%f the filename, %%s the string
Clearing searching having detected this line by setting its value to [nothing] means it's not NOT DEFINED hence no further lines will be reported from the current file, and no further filenames will be examined.
Now if you want to get a listing of ALL of the occurrences of the target lines, all you need to do is to REM-out the SET "searching=" line. Searching will then never be reset, so each line in each file is reported.
If you want some other combination, please clarify.
I have absolutely no idea whatever what you mean by "marking" a line.
#ECHO OFF & setlocal
for /f "tokens=1*delims==" %%i in ('set "$" 2^>nul') do set "%%i="
for %%a in (*.txt) do (
for /f %%b in ('find /v /c "" ^<"%%a"') do echo(%%b lines in %%a.
set /a counter=0, files+=1
for /f "usebackqdelims=" %%b in ("%%~a") do (
set /a counter+=1, total+=1
set "line=%%b"
setlocal enabledelayedexpansion
if not defined $!line! set "$!line!=%%a=!counter!=!line!"
for /f "delims=" %%i in ('set "$" 2^>nul') do (if "!"=="" endlocal)& set "%%i"
)
)
echo(%total% lines in %files% files.
for /f "delims=" %%a in (a) do set "#%%a=%%a"
for /f "tokens=2,3*delims==:" %%i in ('set "$" 2^>nul') do (
if defined #%%k echo("%%k" found in %%i at line %%j.
)
Script can handle !&<>|%, but not =.

Resources