printing a paragraph in windows batch - windows

The following code works pretty well printing the paragraph
#echo off
setlocal disableDelayedExpansion
set "skip="
for /f "delims=:" %%N in (
'findstr /x /n ":::BeginText" "%~f0"'
) do if not defined skip set skip=%%N
>test.txt (
for /f "skip=%skip% tokens=*" %%A in (
'findstr /n "^" "%~f0"'
) do (
set "line=%%A"
setlocal enableDelayedExpansion
echo(!line:*:=!
endlocal
)
)
type test.txt
exit /b
:::BeginText
This text will be exactly preserved with the following limitations:
1) Each line will be terminated by CR LF even if original has only LF.
2) Lines are limited in length to approximately 8191 bytes.
Special characters like ^ & < > | etc. do not cause a problem.
Empty lines are preserved!
;Lines beginning with ; are preserved.
:::Leading : are preserved
Is there a way to add a text marker like :::Endtext so that only the paragraph between
:::BeginText and :::Endtext is printed.

Sure :-)
And you can embed multiple named paragraphs within your script and selectively write them by using a unique label for each.
The named text can appear anywhere within the script as long as GOTO and/or EXIT /B prevent the text from being executed.
The script below encapsulates the logic in a :printParagraph routine for convenience.
#echo off
setlocal disableDelayedExpansion
goto :start
:::BeginText1
Paragraph 1
is preserved
Bye!
:::EndText
:start
echo Print paragraph 1 directly to screen
echo ------------------------------------------
call :printParagraph 1
echo ------------------------------------------
echo(
echo(
call :printParagraph 2 >test.txt
echo Write paragraph 2 to a file and type file
echo ------------------------------------------
type test.txt
echo ------------------------------------------
echo(
echo(
echo Print paragraph 3 directly to screen
echo ------------------------------------------
call :printParagraph 3
echo ------------------------------------------
echo(
echo(
exit /b
:::BeginText2
This is paragraph 2
Pure poetry
:::EndText
:printParagraph
set "skip="
for /f "delims=:" %%N in (
'findstr /x /n ":::BeginText%~1" "%~f0"'
) do if not defined skip set skip=%%N
set "end="
for /f "delims=:" %%N in (
'findstr /x /n ":::EndText" "%~f0"'
) do if %%N gtr %skip% if not defined end set end=%%N
for /f "skip=%skip% tokens=*" %%A in (
'findstr /n "^" "%~f0"'
) do (
for /f "delims=:" %%N in ("%%A") do if %%N geq %end% exit /b
set "line=%%A"
setlocal enableDelayedExpansion
echo(!line:*:=!
endlocal
)
exit /b
:::BeginText3
One more...
...for good measure
:::EndText

Related

Edit text after dot with batch script

I want to remove three digits after dot in last 3 columns with batch file (windows). Note that dots can be present in other columns.
This is a sample of my data:
4216118,'0806010709','ljubičasti ','Hita kirška ambnta',1,'Eriiti (vk, kk)','X','Uđaj za heološke prege','Celyn1800 ','Hni Sak','Hemlogja','2016-06-08 11:42:05.040','2016-06-08 11:41:42.122','2016-06-08 11:49:49.370'
4216081,'0806010387','ljubičasti ','Oća doven.amb. - VANJA',1,'Erii (vk, kk)',,'Urj za heoške prage','Adia 120 R','Reni','Hlogija','2016-06-08 08:52:13.962','2016-06-08 08:51:57.067','2016-06-08 11:08:26.504'
4216667,'1506010909','ljčasti ','tna ambuta kke za invne bolesti',1,'Erciti (vk, kk)',,'Uj za hemloške prge','Cell-Dyn 1800 R','Hi','Hemagija','2016-06-15 21:24:14.646','2016-06-15 21:24:03.523','2016-06-15 21:26:58.871'
4213710,'0905010991','ljubičasti ','Hna kira amnta',1,'Eociti (vk, kk)','X','Uđaj za hemloške prage','Cel1800 ','Hi Sak','Hemlogja','2016-05-09 17:52:32.231','2016-05-09 17:52:26.319','2016-05-09 18:31:33.643'
Example:
Before:
'2016-06-08 11:49:49.370'
After:
'2016-06-08 11:49:49'
#ECHO OFF
SETLOCAL ENABLEDELAYEDEXPANSION
SET "sourcedir=U:\sourcedir"
SET "destdir=U:\destdir"
SET "filename1=%sourcedir%\q47642335.txt"
SET "outfile=%destdir%\outfile.txt"
(
FOR /f "delims=" %%a IN ('more %filename1%') DO (
SET "line=%%a"
ECHO !line:~0,-57!!line:~-53,-31!!line:~-27,-5!!line:~-1!
)
)>"%outfile%"
GOTO :EOF
You would need to change the settings of sourcedir and destdir to suit your circumstances.
I used a file named q47642335.txt containing your data for my testing.
Produces the file defined as %outfile%
Sadly, cmd doesn't play nicely with unicode files, so there will be some modification to the data. Essentially, read each line and pick the line-portions to be concatenated, using - substringing values to select from the end of the line, which is of a consistent structure.
Try this, without any guaranties. Regarding your example, expect you want remove last three digits AND dot, unlike your describe to remove three digits AFTER dot.
#echo off & setlocal ENABLEDELAYEDEXPANSION > out.txt
for /f "tokens=1-15 delims=," %%a in (data.txt) do (
set "string="
call :process "%%a" "%%b" "%%c" "%%d" "%%e" "%%f" "%%g" "%%h" "%%i" "%%j" "%%k" "%%l" "%%m" "%%n" "%%o"
)
exit /B
:process
echo %~1| findstr /R /C:"[0-9]*-[0-9]*-[0-9]* [0-9]*:[0-9]*:[0-9]*\.[0-9][0-9][0-9]" >NUL
if not errorlevel 1 (
set "str=%~1"
set "str=!str:~0,-5!"
if defined string (set "string=!string!,!str!'") else (set "string='!str!'")
) else (
set "str=%~1"
if defined string (set "string=!string!,!str!") else (set "string='!str!'")
)
shift
if not "%~1"=="" (goto :process) else (echo !string!>>out.txt)
GOTO:EOF

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)

Batch file to output lines after string match, filename

I have a directory of thousands of text files that begin with tape* (they're output files from an old Fortran program) and I need to extract 4 lines from each file as well as the filename that they were extracted from. The 4 lines begin 4 lines down from a predictable string, but we can use "Header" for this example:
tape1:
First line
...
Header
Trash1
Trash2
Trash3
Data1
Data2
Data3
Data4
...
I don't care about anything before or after those 4 data lines, but I also want the filename (i.e. "tape1") output after each Data line, like so:
Data1 tape1
Data2 tape1
Data3 tape1
Data4 tape1
Data5 tape2
Data6 tape2
...
Any thoughts on an easy Windows batch file to do this on all tape* files in a directory?
#echo off
setlocal EnableDelayedExpansion
for /F "tokens=1,2 delims=:" %%a in ('findstr /N "Header" tape*') do (
(for /L %%i in (-2,1,%%b) do set /P "="
for /L %%i in (1,1,4) do set /P "line=" & echo !line! %%a
) < "%%a"
)
#echo off
cls
rem get a list of file names sorted alphabetically by name
dir /b tape* /ON>.\Files.txt
rem delete any existing output from any previous run
if exist .\FoundData.txt del .\FoundData.txt
SET DataFileName=
SET LineData=
SET FoundData=
SETLOCAL ENABLEDELAYEDEXPANSION
FOR /F %%A IN (.\Files.txt) DO (
SET DataFileName=%%A
FOR /F "tokens=1,2* " %%B IN (!DataFileName!) DO (
rem use the following line to get just the first word on the line
rem SET LineData=%%B
rem use the following line to get the entire line
SET LineData=%%B %%C %%D
rem determine if the line contains "DATA" (case insensitive) and if so capture it
if "%FoundData%"=="" ( ECHO !LineData!|FIND /I "DATA">Nul && (SET FoundData=!LineData! ) || (SET FoundData=) )
rem if the line contained the data we want output it to the output file
IF NOT "!FoundData!"=="" (
(ECHO !FoundData! !DataFileName!>>.\FoundData.txt)
)
)
SET LineData=
SET FoundData=
)
set DataFileName=
)
ENDLOCAL
if not exist .\FoundData.txt echo No data found>.\FoundData.txt
start notepad .\FoundData.txt
You could try the following:
#echo off
for %%F in (".\tape*.txt") do (
for /F "delims=:" %%N in ('findstr /N /X /C:"Header" "%%~F"') do (
call :SUB "%%~F" %%N
)
)
exit /B
:SUB
set /A "SKIP=%~2+3"
for /F "skip=%SKIP% usebackq delims=" %%L in ("%~1") do (
echo(%%L %~n1
)
exit /B
Here is an alternative approach:
#echo off
for %%F in (".\tape*.txt") do (
for /F %%C in ('^< "%%~F" find /C /V ""') do (
set /A "POS=0" & set "NAME=%%~nF"
< "%%~F" (
setlocal EnableDelayedExpansion
for /L %%I in (1,1,%%C) do (
set "LINE=" & set /P LINE=""
if "!LINE!"=="Header" (
set /A "POS=%%I+3"
)
if !POS! GTR 0 if %%I GTR !POS! (
echo(!LINE! !NAME!
)
)
endlocal
)
)
)

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.

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