Echo specified lines from a text file - windows

This might be an XY question, but I am trying to echo various lines from a text file.
#setlocal enableextensions enabledelayedexpansion
#echo off
set /a "line = 0"
for /f "tokens=* delims= " %%a in (file.txt) do (
set /a "line = line+1"
if !line!==18 set thing1=%%a
if !line!==19 set thing2=%%a
if !line!==20 set thing3=%%a
)
endlocal & set thing1=%thing1% & set thing2=%thing2% & set thing3=%thing3%
echo:
echo %thing1%
echo %thing2%
echo %thing3%
pause
This works well and is neat compared to others I found so I was tiring to to make it more adaptable. I can make the line numbers variable, but what if I wanted four lines, or a range of lines? So I tried to make a for loop.
List all the lines:
(
echo #setlocal enableextensions enabledelayedexpansion
echo #echo off
echo set /a "line = 0"
echo for /f "tokens=* delims= " %%a in (file.txt^) do (
echo set /a "line = line+1"
)>>test.bat
for /l %%m in (1,1,10) do (
echo if !line!==%%m set thing%%m=%%%%a
)>>test.bat
echo )>>test.bat
echo endlocal ^& )>>test.bat
for /l %%m in (1,1,10) do (
echo set thing%%m^=%%thing%%%%m ^&
)>>test.bat
Then I could echo %thing(anynumber%) as I wished.
This runs into problems when the for loop list need to be on the same line:
endlocal & set thing1=%thing1% & set thing2=%thing2% & set thing3=%thing3%
Instead it outputs:
endlocal &
set thing1=%thing%1 &
set thing2=%thing%2 &
set thing3=%thing%3 &
etc...
I know prompt $H can backspace, but I think that is a dead end for what I am trying here. I can't find much on reverse line feed online. Also it adds an ampersand to the final %%thing%% in the list.
Sample file.txt
This is line one
This is line two
This is line three
This is line four
This is line five
This is line six
This is line seven
This is line eight
This is line nine
This is line ten
Maybe findstr is the way to go about this. I found this and edited it to suit what I was trying to do:
:start
cls
set /p "line= Which lines?"
for /f "tokens=* delims=[] " %%a in ('type file.txt^|find /v /n ""') do (
echo/%%a|findstr /l /b "%line%" >nul && echo/%%a
)
pause
goto :start
But with an input of 1 it will echo every instance beginning with "1" i.e. 1,11,12,13 etc. This seems to be nearly there. I've tried various switches from the findstr /?, but can't figure it out. If it could do input ranges too, so input line 1-5,7,12-15 would echo them 10 lines.

This should do (although not with ranges):
#echo off
setlocal
set lines=1,5,6,8
(for %%a in (%lines%) do echo %%a:)>lines.txt
for /f "tokens=1,* delims=:" %%a in ('type file.txt^|findstr /n "^"^|findstr /bg:lines.txt') do echo/%%b
del lines.txt
The first for loop builds a temporary file for findstr /g (see findstr /? for details).
The second one adds line numbers, looks them up in the file and prints the original line if the line number is in the file.
The numbers in %lines% can be delimited by any standard delimiters (TABs, SPACEs, Commas and even = (not recommended - stay with spaces and/or commas)
To expand to Ranges 5-10, you'd need to parse %lines% with some more code (hard to make that fool-proof) and "translate" to single line numbers to write into lines.txt
(We could also expand %lines% to a REGEX search string or findstr, avoiding a temporary file, but it's much easier to understand and maintain this way)
Edit: implemented a simple "range extension" (without checking for plausability):
#echo off
setlocal
set "lines=1,4-6,9"
(for %%a in (%lines%) do (
echo %%a|find "-" >nul && call :range %%a || echo/%%a:
))>lines.txt
echo lines %lines% are:
for /f "tokens=1,* delims=:" %%a in ('type file.txt^|findstr /n "^"^|findstr /bg:lines.txt') do echo/%%b
del lines.txt
goto :eof
:range
for /f "tokens=1,2 delims=-" %%b in ("%1") do (
for /l %%i in (%%b,1,%%c) do echo %%i:
)
goto :eof
Output (with your sample input file):
lines 1,4-6,9 are:
This is line one
This is line four
This is line five
This is line six
This is line nine
PS: this outputs the lines in their original order (set "lines=1,4-6,8" and set "lines=8 1 4-6" give the same output (due to how findstr /g works))

I am not really understanding the arrays. I will have another look next week. So far I've got this based on #Stephan answer.
choice /c rs /m "RANGE MODE OR SPECIFIED MODE"
goto:%errorlevel%
:2
:specified
echo:
set /p lines=ENTER SPECIFIC LINES (seperated by spaces)?
(for %%a in (%lines%) do echo %%a:)>lines.txt
for /f "tokens=1,* delims=:" %%a in (
'type file.txt^|findstr /n "^"^|findstr /bg:lines.txt'
) do (
echo/%%b)
del lines.txt
pause
goto :eof
:1
:range
echo:
set /p ran=ENTER RANGE (e.g. 15-25)?
echo %ran%>range.txt
for /f "tokens=1,* delims=-" %%a in (range.txt) do (
set line1=%%a
set line2=%%b)
del range.txt
(for /l %%a in (%line1%,1,%line2%) do echo %%a:)>lines.txt
for /f "tokens=1,* delims=:" %%a in (
'type file.txt^|findstr /n "^"^|findstr /bg:lines.txt'
) do (
echo/%%b)
del lines.txt
pause
goto :eof
Trying to follow arrays through this link I can see when setting elements within the batch but not pointing file.txt. I tried
for /f %%a in ('type file.txt^|echo !elem[%2%]!') do echo %%a
and
for /f "tokens=* delims=" %%a in ('type file.txt^|find /v /n ""') do (
echo/%%a|findstr /l /b "!elem[%2%]!" >nul && echo echo/%%a)
Anyway that is a different question, I have work through that link next week.

Cuts the number of lines from the top or bottom of file.
This is similar to Unix's Tail command of which there is no Windows' equivalent.
To use
Cut
cut {t|b} {i|x} NumOfLines
Cuts the number of lines from the top or bottom of file.
t - top of the file
b - bottom of the file
i - include n lines
x - exclude n lines
Example
cscript //nologo c:\folder\cut t i 5 < "%systemroot%\win.ini"
Copy following lines into cut.vbs
Set Arg = WScript.Arguments
set WshShell = createObject("Wscript.Shell")
Set Inp = WScript.Stdin
Set Outp = Wscript.Stdout
Set rs = CreateObject("ADODB.Recordset")
With rs
.Fields.Append "LineNumber", 4
.Fields.Append "Txt", 201, 5000
.Open
LineCount = 0
Do Until Inp.AtEndOfStream
LineCount = LineCount + 1
.AddNew
.Fields("LineNumber").value = LineCount
.Fields("Txt").value = Inp.readline
.UpDate
Loop
.Sort = "LineNumber ASC"
If LCase(Arg(1)) = "t" then
If LCase(Arg(2)) = "i" then
.filter = "LineNumber < " & LCase(Arg(3)) + 1
ElseIf LCase(Arg(2)) = "x" then
.filter = "LineNumber > " & LCase(Arg(3))
End If
ElseIf LCase(Arg(1)) = "b" then
If LCase(Arg(2)) = "i" then
.filter = "LineNumber > " & LineCount - LCase(Arg(3))
ElseIf LCase(Arg(2)) = "x" then
.filter = "LineNumber < " & LineCount - LCase(Arg(3)) + 1
End If
End If
Do While not .EOF
Outp.writeline .Fields("Txt").Value
.MoveNext
Loop
End With
For a line count program
Set Arg = WScript.Arguments
set WshShell = createObject("Wscript.Shell")
Set Inp = WScript.Stdin
Set Outp = Wscript.Stdout
Do Until Inp.AtEndOfStream
Line=Inp.readline
Count = Count +1
Loop
outp.writeline Count

Related

Batch list folder contents, then echo results as options to be set as variables

I usually like to try to work these out myself, but at the moment I have to admit I don't know where to start with this one. Hoping someone could kindly steer me in the right direction at least.
I have a folder with a number of .txt files
Text1.txt
Text2.txt
Text3.txt
In my windows bat file I need to list the contents of said folder and set them as options to be set as variables.
example:
cls
echo[
echo[ Please select an option
echo[
echo (1) Text1
echo (2) Text2
echo (3) Text3
echo[
set /p option=Type your selection (1-3) and press ENTER=
if !option!==1 set var=Text1
if !option!==2 set var=Text2
if !option!==3 set var=Text3
Any advice is greatly appreciated, this forum has been great.
*Edit
here is something I tried
cls
echo[
echo[ Please select an option
echo[
dir /b "*.txt"
echo[
set /p option=Type your selection (1-3) and press ENTER=
if !option!==1 set var=text1
if !option!==2 set var=text2
if !option!==3 set var=text3
it works, but does not add the numbers (1) before the options, and it also has them aligned left not centred.
Please select an option
text1.txt
text2.txt
text3.txt
Type your selection (1-3) and press ENTER=
There are different solutions you can build, here are 2 examples.
If you have only a few files you can utilize choice:
#echo off
setlocal enabledelayedexpansion
for /F "tokens=1,*delims=[]" %%i in ('dir /b /a:-d *.txt ^| find /v /n ""') do (
echo %%i. %%j
set "cnt=!cnt!%%i"
set "fchoice%%i=%%~j"
)
choice /c %cnt% /m "Choose"
echo you chose !fchoice%errorlevel%!
if you have many files though, choice might not be a viable option, then revert to set /p:
#echo off
setlocal enabledelayedexpansion
for /F "tokens=1,*delims=[]" %%i in ('dir /b /a:-d *.txt ^| find /v /n ""') do (
echo %%i. %%j
set "cnt=!cnt!%%i"
set "fchoice%%i=%%~j"
set "fin=%%i"
)
set /p "chosen=Select a file by number: "
for /l %%i in (1,1,%fin%) do if "%chosen%" == "%%i" set "check=1"
if not defined check echo Incorrect choice selected & goto :EOF
echo you chose !fchoice%chosen%!
Well, if this were any other language what would you do? Probably populate an array with your directory listing, right? Then use that array to pair menu option with file choice? Well, don't let the fact that the Batch language doesn't have arrays stop you. They're easy enough to simulate.
#echo off & setlocal
rem // init array index
set file.length=0
rem // for each .txt file in the current directory
for %%I in (*.txt) do (
rem // It's good practice only to enable delayed expansion when needed, as
rem // otherwise it can mangle values containing exclamation marks
setlocal enabledelayedexpansion
rem // use a "for /f" command to endlocal while reading the value of
rem // !file.length!. This preserves exclamation marks in file names.
for /f %%# in ("!file.length!") do endlocal & set "file[%%~#]=%%~I"
rem // set /a doesn't require delayed expansion. It just works.
set /a file.ubound = file.length, file.length += 1
)
rem // Display the collection of variables named file...something.
set file
There you go. The last line should show you a list of all the variables beginning with file, including the simulated .length and .ubound properties. From there, just use a for /L %%I in (0, 1, %file.ubound%) to display your menu.
Here's a bit more. Firstly, I read your comment explaining that the number of txt files could exceed 50. By default, the Windows cmd console is 24 lines. Wouldn't it be nice to columnify the output so the user doesn't have to scroll? I wrote a utility script that will take a flat list and columnify it based on the number of rows in the current cmd console. Save this as...
columnify.bat:
#if (#CodeSection == #Batch) #then
#echo off & setlocal
if "%~1"=="test" (
rem // this errors if there's redirected input buffer waiting
timeout /t 0 /nobreak >NUL 2>NUL && (
echo Usage: command list output ^| %~nx0
echo or %~nx0 ^< txtfile containing a list
echo;
echo Hit Ctrl-C to exit.
)
exit
)
for /f "usebackq tokens=1,2 delims=," %%I in (
`powershell "(Get-Host).UI.RawUI.WindowSize.toString()"`
) do (
rem // detect whether input buffer has content waiting
start /b cmd /c "%~f0" test
cscript /nologo /e:JScript "%~f0" %%I %%J
)
goto :EOF
#end // end Batch / begin JScript hybrid code
var stdin = WSH.CreateObject('Scripting.FileSystemObject').GetStandardStream(0).ReadAll();
cols = WSH.Arguments(0) * 1 - 1,
rows = WSH.Arguments(1) * 1 - 4;
var out = stdin.split(/\r?\n/), buffer = [], maxlen, col = 0;
if (rows > out.length) { rows = out.length; }
while (out.length) {
buffer[col] = [];
maxlen = 0;
while (buffer[col].length < rows) {
val = out.length ? out.shift() : '';
buffer[col].push(val);
if (maxlen < val.length) maxlen = val.length;
}
for (var i = buffer[col].length; i--;) {
while (buffer[col][i].length < maxlen) { buffer[col][i] += ' '; }
}
col++;
}
for (var i=0; i < buffer[0].length; i++) {
var line = [];
for (var j=0; j < col; j++) {
line.push(buffer[j][i]);
}
WSH.Echo(line.join(' ').substr(0, cols));
}
Now your main script can make use of columnify.bat by piping output through it.
#echo off & setlocal
rem // All the same stuff as above, but without the comments.
set file.length=0
for %%I in (*.txt) do (
setlocal enabledelayedexpansion
for /f %%# in ("!file.length!") do endlocal & set "file[%%~#]=%%~I"
set /a file.ubound = file.length, file.length += 1
)
cls
:displaymenu
echo Always press your luck. Which file do you choose?
echo;
( for /L %%I in (0,1,%file.ubound%) do #(
call echo %%I: %%file[%%~I]%%
) ) | columnify
echo;
set /P "choice=Enter a number: "
if %choice% GEQ 0 if %choice% LEQ %file.ubound% (
setlocal enabledelayedexpansion
echo You chose !file[%choice%]!. Neat.
endlocal
) else (
cls
powershell "write-host -f red 'Invalid response. Enter a number between 0 and %file.ubound%.'"
goto displaymenu
)

Creating Each line of text as variable and them constantly changing in a loop in batch

So what I'm trying to do is create a find for multiple people where it in the text file it will say names and numbers like
Example of text file:
Beth
1234567891
Jay
2134456544
This is the best way I can explain what I'm trying to do:
#echo off
set "file=Test1.txt"
setlocal EnableDelayedExpansion
<"!file!" (
for /f %%i in ('type "!file!" ^| find /c /v ""') do set /a n=%%i && for /l %%j in (1 1 %%i) do (
set /p "line_%%j="
)
)
set /a Name=1
set /a Number=2
Echo Line_%Name%> %Name%.txt (Im trying to get this to say line_2 to say 1st line in the text file)
Echo Line_%Number%> %Name%.txt (Im trying to get this to say line_2 to say 2nd line in the text file)
:Start
set /a Name=%Name%+2 (These are meant to take off after 1 so lines 3,5,7,9 so on)
set /a Number=%Number%+2 (These are meant to take off after 2 so lines 4,6,8,10 so on)
Echo Line_%Name%
Echo Line_%Number%
GOTO :Start
so the outcome would be
In Beth.txt:
Beth
1234567891
So every name will be a file name and the first line in a file. I will change it later so I can do a addition in each text file.
Name: Beth
Number: 1234567891
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=u:\your files"
SET "destdir=u:\your results"
SET "filename1=%sourcedir%\q65417881.txt"
rem make sure arrays are empty
For %%b IN (name number) DO FOR /F "delims==" %%a In ('set %%b[ 2^>Nul') DO SET "%%a="
rem Initialise counter and entry array
SET /a count=0
SET "number[0]=dummy"
FOR /f "usebackqdelims=" %%a IN ("%filename1%") DO (
IF DEFINED number[!count!] (SET /a count+=1&SET "name[!count!]=%%a") ELSE (SET "number[!count!]=%%a")
)
rem clear out dummy entry
SET "number[0]=dummy"
FOR /L %%c IN (1,1,%count%) DO (
rem replace spaces with dashes
SET "name[%%c]=!name[%%c]: =-!"
rem report to console rem report to console
ECHO Name: !name[%%c]! Number: !number[%%c]!
rem generate name.txt file
(
ECHO !name[%%c]!
ECHO !number[%%c]!
)>"%destdir%\!name[%%c]!.txt"
)
GOTO :EOF
You would need to change the values assigned to sourcedir and destdir to suit your circumstances. The listing uses a setting that suits my system.
I deliberately include spaces in names to ensure that the spaces are processed correctly.
I used a file named q65417881.txt containing your data for my testing.
The line data read from the file is assigned to %%a is assigned to and number[!count!] alternately. The data is retained in these arrays for use by further processing.
[Edited to include conversion of spaces within names to dashes]
If I understand correctly, you want to precede every second line with Number: + SPACE and every other line with Name: + SPACE. For this you do not need to store each line in a variable first, you can use a single for /F loop lo read the file line by line and process every line individually. There are two possibilities:
Temporarily precede every line with a line number plus : using findstr /N:
#echo off
rem // Loop through lines and precede each with line number plus `:`:
for /F "tokens=1* delims=:" %%K in ('findstr /N "^" "Test1.txt"') do (
rem // Calculate remainder of division by two:
set /A "MOD=%%K%%2" 2> nul
rem // Toggle delayed expansion to avoid issues with `!`:
setlocal EnableDelayedExpansion
rem // Conditionally return line string with adequate prefix:
if !MOD! neq 0 (
endlocal & echo Name: %%L
) else (
endlocal & echo Number: %%L
)
)
This will fail when a line begins with the a :.
Check whether numeric representation of current line string is greater than 0:
#echo off
rem // Loop through (non-empty) lines:
for /F "usebackq delims=" %%L in ("Test1.txt") do (
rem // Determine numeric representation of current line string:
set /A "NUM=%%L" 2> nul
rem // Toggle delayed expansion to avoid issues with `!`:
setlocal EnableDelayedExpansion
rem // Conditionally return line string with adequate prefix:
if !NUM! equ 0 (
endlocal & echo Name: %%L
) else (
endlocal & echo Number: %%L
)
)
This fails when a name begins with numerals and/or when a numeric line is 0.
And just for the sake of posting something different:
#SetLocal EnableExtensions DisableDelayedExpansion & (Set LF=^
% 0x0A %
) & For /F %%G In ('Copy /Z "%~f0" NUL') Do #Set "CR=%%G"
#For /F "Tokens=1,2* Delims=:" %%G In ('%__AppDir__%cmd.exe /D/V/C ^
"%__AppDir__%findstr.exe /NR "^[a-Z]*!CR!!LF![0123456789]" "Test1?.txt" 2>NUL"
') Do #(SetLocal EnableDelayedExpansion
(Set /P "=Name: %%I!CR!!LF!Number: " 0<NUL & Set "_="
For /F Delims^=^ EOL^= %%J In ('%__AppDir__%more.com +%%H "%%G"') Do #(
If Not Defined _ Set "_=_" & Echo %%J)) 1>"%%I.txt" & EndLocal)
This file should be run with the Test1.txt file in the current working directory. It is important that along side Test1.txt, there are no other .txt files with the same basename followed by one other character, (for example Test1a.txt or Test12.txt). Should you wish to change your filename, just remember that you must suffix its basename in the above code with a ? character, (e.g. MyTextFile.log ⇒ MyTextFile?.log).
I had the rare opportunity to verify that this script worked against the following example Test1.txt file:
Beth
1234567891
Jay
2134456544
Bob
2137856514
Jimmy
4574459540
Mary
3734756547
Gemma
6938456114
Albert
0134056504

How to get only the first sequence of numbers in a listing using batch or powershell

What I need is the first sequence of a number in a listing:
The command:
for /f "delims=" %%a in (notas.txt) do #echo %%a
Returns:
Compra cfme NF 12345 de 123 CIA ABC
Pgto dupl. 12345 - 123 CIA ABC
Compra cfme NFS 654321-CIA CBC
Pgto NF 654321 de CIA CBC
But what I need is:
12345
12345
654321
654321
Thanks in advance
There are numerous PowerShell solution/techniques that can perform what is required.
The switch statement can be used with the -File and -Regex parameters.
switch -Regex -File notas.txt {
'\d+' { $Matches[0] }
}
You can also use the Match method from the regex class:
Get-Content notas.txt | Foreach-Object {
[regex]::Match($_,'\d+').Value
}
Both solutions rely on regex matching with \d+ matching one or more consecutive digits. Since we are doing a single match per line, the first match is the only match returned. The regex class method Matches returns multiple matches per string input.
With a Batch file using regex in vbscript you can do something like this :
Demo Here
#echo off & color 0A
Title Extract Numbers from String using Regex with vbscript
Set "InputFile=%~dp0notas.txt"
Set "OutPutFile=%~n0_OutPutFile.txt"
Call :Extract_Number "%InputFile%" CON
Call :Extract_Number "%InputFile%" "%OutPutFile%"
TimeOut /T 3 /NoBreak>nul
If Exist "%OutPutFile%" Start "" "%OutPutFile%" & Exit
::-----------------------------------------------------------------------------------
:Extract_Number <Input> <OutPut>
(
echo WScript.StdOut.WriteLine Extract_Number(Data^)
echo Function Extract_Number(Data^)
echo Data = "%~1"
echo Data = WScript.StdIn.ReadAll
echo Set re = New RegExp
echo re.Global = True
echo re.IgnoreCase = True
echo re.Pattern = "\d{5,}"
echo For Each Match in re.Execute(Data^)
echo Number = Number ^& Match.Value ^& vbCrLF
echo Next
echo Extract_Number = Number
echo End Function
)>"%tmp%\%~n0.vbs"
cscript //nologo "%tmp%\%~n0.vbs" < "%~1" > "%~2"
If Exist "%tmp%\%~n0.vbs" Del "%tmp%\%~n0.vbs"
Exit /B
::----------------------------------------------------------------------------------
This first code does what your question asks, but not what your expected results show:
#echo off
:: Pass the entire line to a subroutine
for /f "delims=" %%a in (notas.txt) do call :process %%a
goto :eof
:process
:: Check if we've evaluated the entire line
if "%1"=="" (
echo No number was found in this line
goto :eof
)
:: Check if the current parameter is only numbers
:: If it is, then echo and move on to the next line
:: If not, use shift to evaluate the next parameter
echo %1|findstr /i /r "[^0-9]" >nul && shift && goto :process
echo %1
goto :eof
2 things. First, I don't know what you want to do if a number isn't found in the line. In the code above I just echo "No number was found in this line".
Second, I presumed "number" to be fully delimited with standard spaces as delimiters. Thus, the code above does NOT return 654321 from the line Compra cfme NFS 654321-CIA CBC because 654321-CIA is not a number delimited by spaces. If you want additional delimiters, then change this line above:
for /f "delims=" %%a in (notas.txt) do call :process %%a
to:
for /f "tokens=1-10 delims=-., " %%a in (notas.txt) do call :process %%a %%b %%c %%d %%e %%f %%g %%h %%i %%j
adding whatever delimiters you want (don't forget a space before the double quote). This line is good for up to 10 entries on a given line. Going up to 26 using tokens=1-26 and %%a through %%z is pretty easy.
Finally -- if you want to pull a non-delimited number -- then that would be a completely different approach. An example would be getting 1356 from PC1356 NLA LOA; or getting 35232 from PC LI-D 35232NDA TTH.

sort numbers in text file using command prompt

I wanted to sort numbers in a text file and write the same in another text file for the same I am using the command given below but I am not able to get the output can someone please help me with the same
sort -n test.txt /o output.txt
There is an error message coming up for this as Input file specified two times.
(nice exercise :) )
#echo off
setlocal enabledelayedexpansion
REM convert all numbers to the same lenght by adding leading spaces:
(for /f %%i in (input.txt) do (
REM 12 leading spaces:
set "Z= %%i"
REM take last 12 digits:
echo !Z:~-12!
))>temp.txt
REM sort it:'
sort temp.txt /O temp.txt
REM remove the spaces:
(for /f %%i in (temp.txt) do echo/%%i)>output.txt
del temp.txt
For sure (nice exercise :) ) !!!
Sort numbers in text file using command prompt but not using sort command!!**
#echo off && setlocal enabledelayedexpansion & cd /d "%~dp0"
for /f delims^=:^ tokens^=^2 %%i in ('find /c /v ";" input.txt')do set _cnt=%%i
2>nul (cd.>"%tmp%\_file_.tmp" & cd.>"output.txt") & for /f %%i in (input.txt)do echo/,%%i,>>"%tmp%\_file_.tmp"
for /l %%L in (1 1 99999)do find ",%%L," "%tmp%\_file_.tmp" >nul && (echo/%%L>>"output.txt" & call set /a "_cnt-=1" && if !_cnt! == 0 goto :~0)
:~0
timeout -1 & del "%tmp%\_file_.tmp" & type "output.txt"
:: to count lines / numbers that exist in the file, too, to be used as a run delimiter in for /l ::
for /f delims^=:^ tokens^=^2 %%i in ('find /c /v ";" input.txt')do set _cnt=%%i
:: create the 2 empty files and if they exist, delete the contents ::
2>nul (cd.>"%tmp%\_file_.tmp" & cd.>"output.txt")
:: create unique string for each file number/line "%tmp%\_file_.tmp" ::
for /f %%i in (input.txt)do echo/,%%i,>>"%tmp%\_file_.tmp"
rem :: performs a 1 in 1 to 99999 numeric loop and also finds ",number," in the file "%tmp%\_file_.tmp" ::
rem :: remove ",," (commas) from string, save (if any), only the variable number %%L in "output.txt"
for /l %%L in (1 1 99999)do find ",%%L," "%tmp%\_file_.tmp" >nul && (echo/%%L>>"output.txt" & call set /a "_cnt-=1" && if !_cnt! == 0 goto :~0)
:: for each occurrence, it will be subtracting 1 from the _cnt counter, so when it reaches zero it stops listing/fetching ::
echo/%%L>>"output.txt" & call set /a "_cnt-=1" && if !_cnt! == 0 goto :~0)

Add space character to the end of a particular line

I want to write a vbscript or batch file to run over almost a hundred files (in the same directory) and do the following:
For each line that starts with the string "component " (there is a space after component)
I want to add at the end of that line a space. Other lines won't be affected.
For example:
this is line one
component this is line two
this is line three
will change to:
this is line one
component this is line two (<=space)
this is line three
(There is only one space after the word "two".)
#echo off
for /f "tokens=1,* delims= " %%a in (file.txt) do (
if "%%a"=="component" (
echo %%a %%b >>temp.txt
) else (
echo %%a %%b>>temp.txt
)
)
del file.txt /f /s /q
ren temp.txt file.txt
#Echo OFF
:: By Elektro H#cker
Set "File=Test.txt"
Set "Word=Component"
FOR /F "Usebackq Tokens=* Delims=" %%# IN ("%FILE%") DO (
Echo "%%#"| FINDSTR /I "^\"%WORD%.*\"" >NUL && (
Echo %%# >>".\Output.txt"
) || (
Echo %%#>>".\Output.txt"
)
)
Pause&Exit
In VBScript you could do that with a regular expression:
in = "input.txt"
out = "output.txt"
Set fso = CreateObject("Scripting.FileSystemObject")
text = fso.OpenTextFile(in).ReadAll
text = Replace(text, vbCrLf, vbLf) ' remove CR b/c it interferes with
' multiline matches
Set re = New RegExp
re.Pattern = "^(component .*)$"
re.MultiLine = True
re.Global = True
text = re.Replace(text, "$1 ")
text = Replace(text, vbLf, vbCrLf) ' restore CRLF
fso.OpenTextFile(out, 2, True).Write(text)
fso.DeleteFile in
fso.MoveFile out, in

Resources