I still cannot find a solution to my problem.
What I desire: I have a txt file that contains 16 lines. Those lines begin with . and this is the only thing they have in common. To start with, all the content from line 16 is replaced by the content of line 15 and all line 15 is replaced by line 14 and so forth, until line 2 is replaced by line 1.
Note: the word LINE and numbers are just for reference. In fact, lines can have any alphanumeric character and also some special as - : | *. Lines can also be empty (only having the .)
#echo off
setlocal enabledelayedexpansion
set y=c:\FILES\TEST.txt
set /a count=17
:A
set /a count-=1
The first 'count' should be 16
for /f "delims=. tokens=%count%*" %%r in (%y%) do set L0=%%t
tokens=16 or searches the whole txt for the 16th . character
set L%count%=%L0:~1,133%
variable L16 receives LINE16
echo !L%count%! -^> This must be line %count%
LINE16 -> This must be line 16
if !count!==1 (goto B) else (goto A)
As 16 is not 1, the next 'count' will GOTO A and receive 15
:B
set /a e=17
set /a d=16
:N
set /a e-=1
set /a d-=1
The first 'e' equals to 16 and 'd' equals to 15
call jrepl "!L%e%!" "!L%d%!" /F %y% /M /O -
The first 'count' would replace "!L16!" to "!L15!"
echo !L%e%! -^> This must be line %e%
LINE16 -> This must be line 16
if !e!==2 (goto EOF) else (goto N)
As 16 is not 1, the next 'e' will GOTO N and receive 15
:EOF
echo END
exit/b
Another viewpoint that gives the same output is:
I'll start by saying that I'm astounded that you've got a program/process which writes to the first line of an existing file, overwriting the existing content/without a carriage return.
This solution is similar to Stephans existing answer, but all within one step:
#Echo Off
SetLocal EnableExtensions
Set "y=C:\FILES\TEST.txt"
Rem Create backup.
Copy /Y "%y%" "backup.tmp" 1> NUL 2>&1 || Exit /B
Rem Single step task.
( Echo(
For /F "Tokens=1,* Delims=:" %%G In (
'%__AppDir__%findstr.exe /BLN "." "backup.tmp"^
^| %__AppDir__%findstr.exe /BR "[123456789]: 1[012345]:"'
) Do Echo %%H
) 1> "%y%"
Rem Optionally delete backup.
Rem Del "backup.tmp"
The last line is Remarked, it is a copy of your before file, do not unremark it for actual deletion until you're sure that the resultant test.txt content is what you wanted.
Related
I'm trying to convert a number from a text file - lets say number.txt - from decimal 100 to ASCII 31 30 30.
Is there something I can do in batch?
I tried several things I've found on SO already - but never had the right output.
Later after I have converted that - I need to add one number up after some execution. So lets say after 109 / 31 30 39 - it should be 110 31 31 30 and not 31 30 3a for example.
Can you give me a hint?
setlocal enabledelayedexpansion
for /f "tokens=*" %%a in (nummer.txt) do (
set line=%%a
set a=!line:~0,1!
set line=%%a
set b=!line:~1,1!
set line=%%a
set c=!line:~2,1!
set /a mitte=3!a!3!b!3!c!
echo 0F0900000A00143030303030303030303030303030303030!mitte!00>com3
Please see if the following `Rem`arked batch-file example helps you out.
#Echo Off
SetLocal EnableDelayedExpansion
Rem Undefine any existing variable named inputNum.
Set "inputNum="
Rem Read input number from first line of input file.
Set /P "inputNum="<"nummer.txt"
Rem Exit script if inputNum was not defined.
If Not Defined inputNum GoTo :EOF
Rem Define a number of additional iterations [number results required - 1].
Set "#=9"
Rem Define an increment size.
Set "i=5"
Rem Define a variable for total increase, [# x i].
Set /A $=#*i
Rem Undefine an existing variable named arg.
Set "arg="
Rem Begin looping for stated iterations.
For /L %%G In (0,%i%,%$%)Do (
Set /A arg=inputNum+%%G
Rem Call subfunction passing the input number as an argument.
Call :Sub "!arg!"
Rem If successful,
If Defined mitte (
Rem Output resultant number sequence.
Echo !mitte!
) Else (
Rem Exit if no result sequence.
GoTo EndIt
)
)
:EndIt
Rem Allow time to read output before ending.
Pause
EndLocal
GoTo :EOF
:Sub
Rem Undefine any existing variable named mitte.
Set "mitte="
Rem Split each character of passed argument.
For /F Delims^=^ EOL^= %%G In ('"Cmd /U/C Echo(%~1|Find /V """')Do (
Rem prefix each digit of inputNum with 3.
If Not Defined mitte (Set "mitte=3%%G")Else Set "mitte=!mitte!3%%G")
Rem return to next command line after previous Call
Exit /B
For testing, you should only need to ensure that your input file path is correct, (line 6). I have additionally include a facility to output a specific number of additional iterations, (line 10), with a fixed increment, (line 12). Please adjust those as necessary.
What that does if nummer.txt contains only 401, with 9 additional iterations incrementing by 5 should output:
343031
343036
343131
343136
343231
343236
343331
343336
343431
343436
After testing, you'll probably want to replace Echo !mitte! with (Echo 0F0900000A00143030303030303030303030303030303030!mitte!00)>COM3, (line 26)
#echo off
cls
Color 0A
:Read
setlocal EnableDelayedExpansion
set file=WinSCP-5.11.2-ReadMe.txt
call :ReadInLines
call :EchoLines
echo insert other code here
pause
endlocal
(goto) 2>nul
:ReadInLines
set Counter=0
for /f "DELIMS=" %%i in ('type %file%') do (
set /a Counter+=1
title Lines In File: !Counter!
set "Line_!Counter!=%%i"
)
(goto) 2>nul
:EchoLines
For /L %%C in (1,1,%Counter%) Do (echo %%C. !Line_%%C!)
pause
So this is my code at the moment
It is able to successfully read and output the file as whole but I want to work on a way that doesn't require scrolling (for bigger files)
basically what i need to be able to do is read a certain amount of lines
example:
read lines 1 to 8 but also read lines 5 to 13
basically i need to be able to interchange the numbers it reads to, a label to call is preferred
finished code:
call.bat:
#echo off
cls
Color 0A
:: double call
call text-read-lines-alt.bat 1 8
call text-read-lines-alt.bat 9 20
pause
:: multiselect (a) (b) (a) (b) etc...
call text-read-lines-alt.bat 1 20 23 29
pause
:: call then calling outside text range (outputs first but not second)
call text-read-lines-alt.bat 1 8
call text-read-lines-alt.bat 80 100
pause
:: another call outside text range (outputs nothing)
call text-read-lines-alt.bat 90 100
pause
text-read-lines-alt.bat:
#echo off
setlocal EnableDelayedExpansion
set file=WinSCP-5.11.2-ReadMe.txt
SET "parms=%*"
call :ReadInLines
call :EchoLines
echo insert other code here
endlocal
(goto) 2>nul
:ReadInLines
set Counter=0
for /f "DELIMS=" %%i in ('type %file%') do (
set /a Counter+=1
title Lines In File: !Counter!
CALL :gate !counter!
IF DEFINED RECORD set "Line_!Counter!=%%i"
)
(goto) 2>nul
:EchoLines
For /L %%C in (1,1,%Counter%) Do IF DEFINED line_%%C (echo %%C. !Line_%%C!)
GOTO :EOF
:gate
SET "record="
IF NOT DEFINED parms GOTO :EOF
FOR /f "tokens=1,2*" %%x IN ("%parms%") DO (
IF %1 gtr %%y SET "parms=%%z"&GOTO gate
IF %1 geq %%x SET "record=Y"
)
GOTO :EOF
and here is what all the hard work went to: http://old-school-gamer.tk/batch/text-reader/releases/
:D
#ECHO OFF
setlocal EnableDelayedExpansion
set file=WinSCP-5.11.2-ReadMe.txt
set file=100lines.txt
SET "parms=%*"
call :ReadInLines
call :EchoLines
echo insert other code here
pause
endlocal
(goto) 2>nul
:ReadInLines
set Counter=0
for /f "DELIMS=" %%i in ('type %file%') do (
set /a Counter+=1
title Lines In File: !Counter!
CALL :gate !counter!
IF DEFINED RECORD set "Line_!Counter!=%%i"
)
(goto) 2>nul
:EchoLines
For /L %%C in (1,1,%Counter%) Do IF DEFINED line_%%C (echo %%C. !Line_%%C!)
SET /a count=0
For /L %%C in (1,1,%Counter%) Do IF DEFINED line_%%C (
SET /a count +=1
echo !count!. !Line_%%C!
)
GOTO :EOF
:gate
SET "record="
IF NOT DEFINED parms GOTO :EOF
FOR /f "tokens=1,2*" %%x IN ("%parms%") DO (
IF %1 gtr %%y SET "parms=%%z"&GOTO gate
IF %1 geq %%x SET "record=Y"
)
GOTO :EOF
I started by recording parms=the command-tail. My 100lines.txt file is simply a file containing 100 lines "line 1".."line100"
CALLing the :gate procedure sets or clears record to specify whether the line in counter should be recorded or not. if defined works on the current status of the target variable - defined or not.
The :gate routine examines the parms string, assigning %%x to the first token, %%y to the second and %%z to the remainder of the parameters provided. If the current line number in %1 (from the calling loop) is greater then the second parameter, then assign parms to the rest of the string (which removes thefirst two parameters) and try again. parms will eventually become empty, so simply don't try processing it.
If the second parameter is not greater than the current line, see whether the current line is greater than or equal to the first parameter. If so, set record to a value so it becomes defined and hence the calling loop will record it.
So - say params is 10 13 21 28. %%x will be set to 10, %%y to 13 and %%z to 21 28. Until line 9, the line number will not be geq 10, so record remains clear. For lines 10 to 13, record will be set and the line recorded, on line 14, 14 is greater than 13, so parms becomes 21 28 and we try again.
I've modified the output procedure too. the if defined gate will only execute the echo if line_%%C is defined, so there'll be no empty lines. The downside is that the report will show the line number from the file.
The second procedure uses a fairly obvious method to serialise the output to produce the line numbers.
For example,
If the datafile contains
Line 1
Line 2
Line 3
Line 4
Line 5
Line 6
Line 7
Line 8
then if the parameters supplied are 3 5 meaning "lines 3 to 5 inclusive" then the output from
For /L %%C in (1,1,%Counter%) Do IF DEFINED line_%%C (echo %%C. !Line_%%C!)
will be
Line 3
Line 4
Line 5
(note each line has its original line number.
and the output from
SET /a count=0
For /L %%C in (1,1,%Counter%) Do IF DEFINED line_%%C (
SET /a count +=1
echo !count!. !Line_%%C!
)
will be
Line 3
Line 4
Line 5
(simply the same data but with the line numbers modified)
if you leave both of these output mechanisms in place, the output will be
Line 3
Line 4
Line 5
Line 3
Line 4
Line 5
that is, the first output concatenated with the second.
Hope msr.exe can help you for such file text processing.
msr -p file-paths -L begin-line -N end-line with -PAC to hide path/info/color.
But cannot read 2 ranges(read lines 1 to 8 but also read lines 5 to 13) at one time:
msr -p test.txt -L 1 -N 8 + msr -p text.txt -L 5 -N 13
See following screenshot.
msr.exe/msr.gcc* is a single exe tool about 1.5MB no dependencies for file/pipe text processing on Windows and Linux in my open project. See docs like peformance comparision with grep and findstr and built-in usage doc by running exe etc.
When I use this code to select a character from my list, it works just fine but when I write it to a file using:
echo %pwd%>>pwd.gen
It will some times put the word "ECHO" randomly in the middle of the strings generated. Here is an example:
jUrkunjcxC
ecRECHOsI5w0T
DmJfat13fT
UWXOysW7Gb
pPmS7138Ve
nFkh32ECHOJd1
You can see it appears in line 2 and 6. This only happens about 20% of the time.
Here is the code:
#echo off
title Password Generator
color f0
:firstRun
set /a cnt=0
cls
setlocal ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION
set /p Len=What length should the password be?
set /a Len=%Len%-1
cls
set /p Amt=How many would you like to generate?
cls
goto start
:start
set alfanum=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
set pwd=
FOR /L %%b IN (0, 1, %Len%) DO (
SET /A rnd_num=!RANDOM! * 62 / 32768 + 1
for /F %%c in ('echo %%alfanum:~!rnd_num!^,1%%') do set pwd=!pwd!%%c
)
echo %pwd%>> pwd.gen
set /a cnt=%cnt%+1
if %cnt%==%Amt% goto end
goto start
:end
cls
echo Done!
echo Results have been saved to "pwd.gen"
echo.
choice /c YN /m "Restart?"
if %errorlevel%==1 goto firstRun
:start
set alfanum=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789
set pwd=
FOR /L %%b IN (0, 1, %Len%) DO (
SET /A rnd_num=!RANDOM! * 62 / 32768 + 1
for /F %%c in ('echo %%alfanum:~!rnd_num!^,1%%') do set pwd=!pwd!%%c
)
alfanum is 26+26+10 = 62 characters long.
RANDOM gives a random number from 0-32,767
When RANDOM is above 32240, rnd_num gets set to 62
string indexing starts at 0 not 1
the for /F %%c command indexes alfanum:~62,1~ which is an empty string
it calls echo with no parameter, which prints ECHO is on. instead of returning a single character
for /F defaults to splitting strings with a space delimiter, which separates out the first word
%%c becomes ECHO
you add ECHO into the password.
This is a combination of a couple of things. While I'm not totally clear about the inner workings of the whole thing, I know what's causing it and how to fix it.
ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789 is 62 characters long. However, substrings in batch start with 0, so valid numbers go from 0 to 61. For whatever reason, an index-out-of-range combined with the ^ in 'echo %%alfanum:~!rnd_num!^,1%%' is causing the word ECHO to be displayed.
To get around this, simply don't add 1 when calculating rnd_num.
SET /A rnd_num=!RANDOM! * 62 / 32768
Okay, I know this is purely academic because the findstr command can do what I expect in a jiffy.
I have a text file whose strings (lines) I want numbered. I was wondering whether it's possible to write a batch that emulates it and gives me the flexibility of moving the tagging integer anywhere in the string.
For example the standard output is 1: some string
Let us say I want
1)some string (without using find and replace in Windows Explorer), or
somestring........(1), or
s 1] somestring
EDIT: I modified the code in order to insert the line number at any place in the line:
#echo off
setlocal DisableDelayedExpansion
rem Define the format of output lines; for example
rem To show "(lineNo) line" use:
set "format=(!lineNo!) !line!"
rem To show "20 chars of line (lineNo) rest of line" use:
set "format=!line:~0,20! (!lineNo!) !line:~20!"
rem and adjust each line read appending 20 spaces
rem To show "line (lineNo placed at column 75)" use:
set "format=!line:~0,73! (!lineNo!)"
rem and adjust each line read appending 73 spaces
rem To show line numbers with left zeros, start lineNo with the proper
rem number of zeros and modify the format accordingly; for example:
set lineNo=100
set "format=!line:~0,73! (!lineNo:~1!)"
setlocal EnableDelayedExpansion
copy %1 "%~1.tmp" > NUL
set "EOF=%random%%random%%random%"
echo :%EOF%EOF:>> "%~1.tmp"
REM set lineNo=0
call :ReadLines < "%~1.tmp"
del "%~1.tmp"
goto :EOF
:ReadLines
set "line="
set /P "line="
if "!line!" equ ":%EOF%EOF:" goto :EOF
set "line=!line! "
set /A lineNo+=1
echo %format%
goto ReadLines
Output example:
#echo off (01)
setlocal DisableDelayedExpansion (02)
(03)
rem Define the format of output lines; for example (04)
(05)
rem To show "(lineNo) line" use: (06)
set "format=(!lineNo!) !line!" (07)
(08)
rem To show "20 chars of line (lineNo) rest of line" use: (09)
set "format=!line:~0,20! (!lineNo!) !line:~20!" (10)
rem and adjust each line read appending 20 spaces (11)
(12)
rem To show "line (lineNo placed at column 75)" use: (13)
set "format=!line:~0,73! (!lineNo!)" (14)
rem and adjust each line read appending 73 spaces (15)
(16)
rem To show line numbers with left zeros, start lineNo with the proper (17)
rem number of zeros and modify the format accordingly; for example: (18)
set lineNo=100 (19)
set "format=!line:~0,73! (!lineNo:~1!)" (20)
(21)
(22)
setlocal EnableDelayedExpansion (23)
copy %1 "%~1.tmp" > NUL (24)
set "EOF=%random%%random%%random%" (25)
echo :%EOF%EOF:>> "%~1.tmp" (26)
REM set lineNo=0 (27)
call :ReadLines < "%~1.tmp" (28)
del "%~1.tmp" (29)
goto :EOF (30)
(31)
:ReadLines (32)
set "line=" (33)
set /P "line=" (34)
if "!line!" equ ":%EOF%EOF:" goto :EOF (35)
set "line=!line! (36)
set /A lineNo+=1 (37)
echo %format% (38)
goto ReadLines (39)
#echo off
SET SNO=1
FOR /f "tokens=*" %%X IN (friends.txt) DO (call :subroutine %%X)
GOTO :eof
:subroutine
:: This is the interesting part where the value of the SNO can be
:: moved around.If you want the SNO bang in the middle then
:: then that that's another project ! Moreover moving it to the end
:: is problematic if the strings don't have the same number
:: of characters. The result is not visually pleasant in that case
echo.
echo (%SNO%) %1>>numbered.txt
set /a SNO+=1
GOTO :eof
I have a simple text file with numbers like:
12345
45678
34567
89101
I need a batch that will return the nth line from this file. n should be taken from a command line argument.
I am very new to batch scripting so Thanks in advance for any help on this.
To get the file from the nth line you could use more +n (For line1 is n=0).
To split the rest of the file you could use a FOR /F loop.
This works even, if there are empty lines before the nth line.
It could be necessary to set the EOL to an unused character or to linefeed (default is ;)
set "lineNr=%1"
set /a lineNr-=1
for /f "usebackq delims=" %%a in (`more +%lineNr% text.txt`) DO (
echo %%a
goto :leave
)
:leave
You can use batch file extension.
token.bat
#echo off
setlocal ENABLEDELAYEDEXPANSION
set l=%1
set c=0
for /f "delims=" %%1 in ('type foo.txt') do (
set /a c+=1 && if "!c!" equ "%l%" echo %%1%
)
If you have a file like following,
foo.txt
AAAA
BBBB
CCCC
DDDD
And specify line number like following
token 3
You'll get
CCCC
You could use FOR /F with the skip parameter:
#ECHO OFF
SET skip=%1
SET /A skip-=1
IF %skip% LSS 0 GOTO out
IF %skip% GTR 0 SET params="skip=%skip%"
FOR /F %params% %%L IN (filename) DO (SET "line=%%L"& GOTO out)
:out
ECHO %line%
The skip parameter means the FOR /F loop must skip the specified number of lines at the beginning. The parameter is only applied if you specify a line number greater than 1. If you specify a number less than one or a non-number, the script outputs an empty string.
+1 for Jeb's solution... I did not realize you could use the more command to skip lines like that!
Here is an alternate method that I use for getting a specific line from a file (or from the multi-line output of another program):
#echo off
for /f "tokens=1* delims=:" %%a in ('findstr /n .* "C:\SomeFile.txt"') do (
if "%%a" equ "%1" echo.%%b
)
I use findstr /n .* "Path\FileName.ext" to add line numbers, and to ensure no empty lines are skipped by the for loop.
I then set "tokens=1* delims=:" to separate the line numbers from the line content.
Finally, I compare the current line number (%%a) with the line specified by the %1 parameter, and echo the line contents (%%b) on a match.
To Find Nth to Mth Character In Line No. L --- Example For Finding Label
#echo off
REM Next line = Set command value to a file OR Just Choose Your File By Skipping The Line
vol E: > %temp%\justtmp.txt
REM Vol E: = Find Volume Lable Of Drive E
REM Next Line to choose line line no. +0 = line no. 1
for /f "usebackq delims=" %%a in (`more +0 %temp%\justtmp.txt`) DO (set findstringline=%%a& goto :nextstep)
:nextstep
REM Next line to read nth to mth Character here 22th Character to 40th Character
set result=%findstringline:~22,40%
echo %result%
pause
exit /b
Save as find label.cmd
The Result Will Be Your Drive E Label
Enjoy
Based off of Amit's Answer, I made a utility called snip.cmd.
USAGE: snip FILE LINE FIRSTCHARACTER LASTCHARACTER
example:
foo.txt
//
// File Checksum Integrity Verifier version 2.05.
//
77752e4c91ba96dcc6c2bb4bdcdbdec5 c:\users\lapinot\desktop\token.bat
snip foo.txt 3 0 33 will yield 77752e4c91ba96dcc6c2bb4bdcdbdec5
Here is my code for snipe.cmd (you can add snipe to your command line by copying snip.cmd to c:\Windows\System32):
#echo off
:: USAGE
:: snip <file> [Line - Starts at 0] [First Column - Start Count at 0] [Last Colum]
set file=%1
set line=%2
set char1=%3
set char2=%4
for /f "usebackq delims=" %%a in (`more +%line% %file%`) DO (set findstringline=%%a& goto :nextstep)
:nextstep
echo echo %%findstringline:^~%char1%,%char2%%% > %temp%\result.bat
%temp%\result.bat
del %temp%\result.bat
:EOF
exit /b
echo "enter the line number.."; read i; awk 'NR==$i' <file_name>;