npocmaka
Probably there are other implementations of tail , but I couldn't find:
Code: Select all
@echo off
setlocal
if "%~2" equ "" echo USAGE: %~n0 file lines && exit /b 2
if not exist "%~1" echo file does not exists && exit /b 1
set /a lines=%~2
setlocal enableDelayedExpansion
for /f "tokens=1,2* delims=:" %%L in ('findstr /R /N "^" "%~1"') do (
if %%L LEQ %lines% (
endlocal
echo/ %%M
) else (
goto :endfor
)
)
:endfor
endlocal
endlocal
Last edited by npocmaka (23 May 2013 13:08)
----------------------------
#2 22 May 2013 07:43
jeb
Hi npocmaka,
Disable delayed expansion and this problem is gone.npocmaka wrote:
And !s are not processed well.
BUT there are still some others.
You strip all leading colons from any line.
With "echo/ %%M" you prefix each line with a space and it fails for a line containing a single "?",
better use "echo(%%M" here.
You could use the "set/p" technic to read the lines or the FOR/F delayed toggling technic.
jeb
Last edited by jeb (22 May 2013 07:46)
----------------------------
#3 22 May 2013 08:37
npocmaka
Thanks!
improved:
Code: Select all
@echo off
setlocal
if "%~2" equ "" echo USAGE: %~n0 file lines && exit /b 2
if not exist "%~1" echo file does not exists && exit /b 1
set /a lines=%~2
setlocal enableDelayedExpansion
for /f "tokens=1,2* delims=:" %%L in ('findstr /R /N "^" "%~1"') do (
if %%L LEQ %lines% (
setlocal disableDelayedExpansion
echo\%%M
endlocal
) else (
goto :endfor
)
)
:endfor
endlocal
endlocal
And the possibility of breaking parentheses context makes me sick

Will try another implementations later...
----------------------------
#4 22 May 2013 08:53
jeb
Hmmm, why are you toggling delayed expansion? Your code don't need it at all.
No. echo( never breaks the parentheses context.npocmaka wrote:
And the possibility of breaking parentheses context makes me sick.Prefer to use echo? or echo\ instead of echo(
But echo\ fails with "..\..\..\windows\system32\calc.exe" in %%M
Code: Select all
@echo off
setlocal DisableDelayedExpansion
set /a lines=%~2
for /F "delims=" %%L in ('findstr /R /N "^" "%~1"') do (
set "line=%%L"
for /F "delims=:" %%n in ("%%L") do (
if %%n LEQ %lines% (
setlocal EnableDelayedExpansion
set "text=!line:*:=!"
(echo(!text!)
endlocal
) ELSE goto :break
)
)
:break
#5 22 May 2013 09:06
npocmaka
great

Didn't find way to break it.And it can be easy enhanced to show the lines from the end...
----------------------------
#6 22 May 2013 09:32
npocmaka
and the enhanced edition (if the number of lines is negative shows the last lines):
Code: Select all
@echo off
if "%~2" equ "" echo USAGE: %~n0 file lines && exit /b 2
if not exist "%~1" echo file does not exists && exit /b 1
setlocal DisableDelayedExpansion
set /a lines=%~2
if %lines% LSS 0 (
for /F %%C in ('findstr /R /N "^" "%~1" ^| find /C ":"') do set line_count=%%C && goto :backward
)
for /F "delims=" %%L in ('findstr /R /N "^" "%~1"') do (
set "line=%%L"
for /F "delims=:" %%n in ("%%L") do (
if %%n LEQ %lines% (
setlocal EnableDelayedExpansion
set "text=!line:*:=!"
(echo(!text!)
endlocal
) ELSE goto :break
)
)
:break
endlocal
exit /b 0
:backward
set /a start_line=%line_count%%lines%
for /F "delims=" %%L in ('findstr /R /N "^" "%~1"') do (
set "line=%%L"
for /F "delims=:" %%n in ("%%L") do (
if %%n GEQ %start_line% (
setlocal EnableDelayedExpansion
set "text=!line:*:=!"
(echo(!text!)
endlocal
)
)
)
endlocal
exit /b 0
----------------------------
#7 22 May 2013 09:37
foxidrive
On recent Windows this works - 65K lines generates a pause but that's the only issue.
for line 120 and onward
Code: Select all
More +120 "file.txt"
#8 22 May 2013 12:18
dbenham
Actually the above will pause after every screen unless the MORE output is either redirected or piped. But I believe you are correct that even piped or redirected output will pause at some point.foxidrive wrote:
On recent Windows this works - 65K lines generates a pause but that's the only issue.
for line 120 and onward
Code: Select all
More +120 "file.txt"
Unfortunately the pause is not the only issue.
MORE converts TABs into a series of SPACEs, and there is no way to prevent MORE from doing that. That may or may not be a problem.
Dave Benham
----------------------------
#9 22 May 2013 12:37
foxidrive
Confirmed fwiw. That's a bugger. Win 8 converts a tab at the start of a line into 8 spaces.dbenham wrote:
MORE converts TABs into a series of SPACEs, and there is no way to prevent MORE from doing that. That may or may not be a problem.
There are so many gotcha's in batch - I think that's why we like it.

----------------------------
#10 23 May 2013 13:12
npocmaka
First release candidate .More I look at this more it looks like something that can be simplified

(it accepts two arguments BEGIN and END for the lines beyond the file.If some of arguments is negative it will start from the end).Still not extensive tested.
Code: Select all
@echo off
setlocal
rem ---------------------------
rem ------ arg parsing --------
rem ---------------------------
if "%~1" equ "" goto :help
for %%H in (/h -h /help -help) do (
if /I "%~1" equ "%%H" goto :help
)
setlocal enableDelayedExpansion
set "prev="
for %%A in (%*) do (
if /I "!prev!" equ "-file" set file=%%~fsA
if /I "!prev!" equ "-begin" set begin=%%~A
if /I "!prev!" equ "-end" set end=%%~A
set prev=%%~A
)
endlocal & (
if "%file%" neq "" (set file=%file%)
if "%begin%" neq "" (set /a begin=%begin%)
if "%end%" neq "" (set /a end=%end%)
)
rem -----------------------------
rem --- invalid cases check -----
rem -----------------------------
if "%file%" EQU "" echo file not defined && exit /b 1
if not exist "%file%" echo file not exists && exit /b 2
if not defined begin if not defined end echo neither BEGIN line nor END line are defined && exit /b 3
rem --------------------------
rem -- function selection ----
rem --------------------------
if defined begin if %begin%0 LSS 0 for /F %%C in ('findstr /R /N "^" "%file%" ^| find /C ":"') do set /a lines_count=%%C
if defined end if %end%0 LSS 0 if not defined lines_count for /F %%C in ('findstr /R /N "^" "%file%" ^| find /C ":"') do set lines_count=%%C
if not defined begin if defined end if %end%0 GEQ 0 goto :positive_end_only
if not defined begin if defined end if %end%0 LSS 0 goto :negative_end_only
if not defined end if defined begin if %begin%0 GEQ 0 goto :positive_begin_only
if not defined end if defined begin if %begin%0 LSS 0 goto :negative_begin_only
if %begin%0 LSS 0 if %end%0 LSS 0 goto :negative_negative
if %begin%0 LSS 0 if %end%0 GEQ 0 goto :negative_positive
if %begin%0 GEQ 0 if %end%0 LSS 0 goto :positive_negative
if %begin%0 GEQ 0 if %end%0 GEQ 0 goto :positive_positive
goto :eof
rem -------------------------
rem ------ functions --------
rem -------------------------
rem ----- single cases -----
:positive_begin_only
setlocal disableDelayedExpansion
for /F "delims=" %%L in ('findstr /R /N "^" "%file%"') do (
set "line=%%L"
for /F "delims=:" %%n in ("%%L") do (
IF %%n GEQ %begin% (
setlocal EnableDelayedExpansion
set "text=!line:*:=!"
(echo(!text!)
endlocal
)
)
)
endlocal
endlocal
goto :eof
:negative_begin_only
setlocal DisableDelayedExpansion
set /a begin_line=%lines_count%%begin%+1
for /F "delims=" %%L in ('findstr /R /N "^" "%file%"') do (
set "line=%%L"
for /F "delims=:" %%n in ("%%L") do (
if %%n GEQ %begin_line% (
setlocal EnableDelayedExpansion
set "text=!line:*:=!"
(echo(!text!)
endlocal
)
)
)
endlocal
endlocal
goto :eof
:positive_end_only
setlocal disableDelayedExpansion
for /F "delims=" %%L in ('findstr /R /N "^" "%file%"') do (
set "line=%%L"
for /F "delims=:" %%n in ("%%L") do (
IF %%n LEQ %end% (
setlocal EnableDelayedExpansion
set "text=!line:*:=!"
(echo(!text!)
endlocal
) ELSE goto :break_peo
)
)
:break_peo
endlocal
endlocal
goto :eof
:negative_end_only
setlocal disableDelayedExpansion
set /a end_line=%lines_count%%end%+1
for /F "delims=" %%L in ('findstr /R /N "^" "%file%"') do (
set "line=%%L"
for /F "delims=:" %%n in ("%%L") do (
IF %%n LEQ %end_line% (
setlocal EnableDelayedExpansion
set "text=!line:*:=!"
(echo(!text!)
endlocal
) ELSE goto :break_neo
)
)
:break_neo
endlocal
endlocal
goto :eof
rem --- end and begin cases -----
:negative_negative
setlocal disableDelayedExpansion
set /a end_line=%lines_count%%end%+1
set /a begin_line=%lines_count%%begin%+1
if %begin_line% GTR %end_line% goto :break_nn
for /F "delims=" %%L in ('findstr /R /N "^" "%file%"') do (
set "line=%%L"
for /F "delims=:" %%n in ("%%L") do (
IF %%n GEQ %begin_line% (
IF %%n LEQ %end_line% (
setlocal EnableDelayedExpansion
set "text=!line:*:=!"
(echo(!text!)
endlocal
) ELSE goto :break_nn
)
)
)
:break_nn
endlocal
endlocal
goto :eof
:negative_positive
setlocal disableDelayedExpansion
set /a begin_line=%lines_count%%begin%+1
if %begin_line% GTR %end% goto :break_nn
for /F "delims=" %%L in ('findstr /R /N "^" "%file%"') do (
set "line=%%L"
for /F "delims=:" %%n in ("%%L") do (
IF %%n GEQ %begin_line% (
IF %%n LEQ %end% (
setlocal EnableDelayedExpansion
set "text=!line:*:=!"
(echo(!text!)
endlocal
) ELSE goto :break_np
)
)
)
:break_np
endlocal
endlocal
goto :eof
:positive_negative
echo oioioi
setlocal disableDelayedExpansion
set /a end_line=%lines_count%%end%+1
if %begin% GTR %end_line% goto :break_nn
for /F "delims=" %%L in ('findstr /R /N "^" "%file%"') do (
set "line=%%L"
for /F "delims=:" %%n in ("%%L") do (
IF %%n GEQ %begin% (
IF %%n LEQ %end_line% (
setlocal EnableDelayedExpansion
set "text=!line:*:=!"
(echo(!text!)
endlocal
) ELSE goto :break_pn
)
)
)
:break_pn
endlocal
endlocal
goto :eof
:positive_positive
setlocal disableDelayedExpansion
if %begin% GTR %end% goto :break_nn
for /F "delims=" %%L in ('findstr /R /N "^" "%file%"') do (
set "line=%%L"
for /F "delims=:" %%n in ("%%L") do (
IF %%n GEQ %begin% (
IF %%n LEQ %end% (
setlocal EnableDelayedExpansion
set "text=!line:*:=!"
(echo(!text!)
endlocal
) ELSE goto :break_pp
)
)
)
:break_pp
endlocal
endlocal
goto :eof
rem ------------------
rem --- HELP ---------
rem ------------------
:help
echo(
echo %~n0 - dipsplays a lines of a file defined by -BEGIN and -END arguments passed to it
echo(
echo( USAGE:
echo(
echo %~n0 -file=file_to_process {-begin=begin_libe ^| -end=end_line }
echo or
echo %~n0 -file file_to_process {-begin begin_libe ^| -end end_line }
echo(
echo( if some of arguments BEGIN or END has a negative number it will start to count from the end of file
echo(
echo( http://ss64.org/viewtopic.php^?id^=1707
goto :eof
----------------------------
#11 29 May 2013 09:42
npocmaka
And here is a little bit improved version plus version that uses FOR /F - both are fairly the same. The second version should be faster , but i didn't make tests yet.Soon will create also SET /P version and will think about performance improvements (if it's possible).Still both versions set one additional empty line at the end.Will be glad to hear/red any feedback

FINDSTR version
Code: Select all
@echo off
setlocal
rem ---------------------------
rem ------ arg parsing --------
rem ---------------------------
if "%~1" equ "" goto :help
for %%H in (/h -h /help -help) do (
if /I "%~1" equ "%%H" goto :help
)
setlocal enableDelayedExpansion
set "prev="
for %%A in (%*) do (
if /I "!prev!" equ "-file" set file=%%~fsA
if /I "!prev!" equ "-begin" set begin=%%~A
if /I "!prev!" equ "-end" set end=%%A
set prev=%%~A
)
endlocal & (
if "%file%" neq "" (set file=%file%)
if "%begin%" neq "" (set /a begin=%begin%)
if "%end%" neq "" (set /a end=%end%)
)
rem -----------------------------
rem --- invalid cases check -----
rem -----------------------------
if "%file%" EQU "" echo file not defined && exit /b 1
if not exist "%file%" echo file not exists && exit /b 2
if not defined begin if not defined end echo neither BEGIN line nor END line are defined && exit /b 3
rem --------------------------
rem -- function selection ----
rem --------------------------
if defined begin if %begin%0 LSS 0 for /F %%C in ('find /c /v "" ^<"%file%"') do set /a lines_count=%%C
if defined end if %end%0 LSS 0 if not defined lines_count for /F %%C in ('find /c /v "" ^<"%file%"') do set lines_count=%%C
rem -- begin only
if not defined begin if defined end if %end%0 GEQ 0 goto :end_only
if not defined begin if defined end if %end%0 LSS 0 (
set /a end=%lines_count%%end%+1
goto :end_only
)
rem -- end only
if not defined end if defined begin if %begin%0 GEQ 0 goto :begin_only
if not defined end if defined begin if %begin%0 LSS 0 (
set /a begin=%lines_count%%begin%+1
goto :begin_only
)
rem -- begin and end
if %begin%0 LSS 0 if %end%0 LSS 0 (
set /a begin=%lines_count%%begin%+1
set /a end=%lines_count%%end%+1
goto :begin_end
)
if %begin%0 LSS 0 if %end%0 GEQ 0 (
set /a begin=%lines_count%%begin%+1
goto :begin_end
)
if %begin%0 GEQ 0 if %end%0 LSS 0 (
set /a end=%lines_count%%end%+1
goto :begin_end
)
if %begin%0 GEQ 0 if %end%0 GEQ 0 (
goto :begin_end
)
goto :eof
rem -------------------------
rem ------ functions --------
rem -------------------------
rem ----- single cases -----
:begin_only
setlocal DisableDelayedExpansion
for /F "delims=" %%L in ('findstr /R /N "^" "%file%"') do (
set "line=%%L"
for /F "delims=:" %%n in ("%%L") do (
if %%n GEQ %begin% (
setlocal EnableDelayedExpansion
set "text=!line:*:=!"
(echo(!text!)
endlocal
)
)
)
endlocal
endlocal
goto :eof
:end_only
setlocal disableDelayedExpansion
for /F "delims=" %%L in ('findstr /R /N "^" "%file%"') do (
set "line=%%L"
for /F "delims=:" %%n in ("%%L") do (
IF %%n LEQ %end% (
setlocal EnableDelayedExpansion
set "text=!line:*:=!"
(echo(!text!)
endlocal
) ELSE goto :break_eo
)
)
:break_eo
endlocal
endlocal
goto :eof
rem --- end and begin case -----
:begin_end
setlocal disableDelayedExpansion
if %begin% GTR %end% goto :break_be
for /F "delims=" %%L in ('findstr /R /N "^" "%file%"') do (
set "line=%%L"
for /F "delims=:" %%n in ("%%L") do (
IF %%n GEQ %begin% IF %%n LEQ %end% (
setlocal EnableDelayedExpansion
set "text=!line:*:=!"
(echo(!text!)
endlocal
) ELSE goto :break_be
)
)
:break_be
endlocal
endlocal
goto :eof
rem ------------------
rem --- HELP ---------
rem ------------------
:help
echo(
echo %~n0 - dipsplays a lines of a file defined by -BEGIN and -END arguments passed to it
echo(
echo( USAGE:
echo(
echo %~n0 -file=file_to_process {-begin=begin_line ^| -end=end_line }
echo or
echo %~n0 -file file_to_process {-begin begin_line ^| -end end_line }
echo(
echo( if some of arguments BEGIN or END has a negative number it will start to count from the end of file
echo(
echo( http://ss64.org/viewtopic.php^?id^=1707
echo(
goto :eof
FOR /Fversion
@echo off
setlocal
rem ---------------------------
rem ------ arg parsing --------
rem ---------------------------
if "%~1" equ "" goto :help
for %%H in (/h -h /help -help) do (
if /I "%~1" equ "%%H" goto :help
)
setlocal enableDelayedExpansion
set "prev="
for %%A in (%*) do (
if /I "!prev!" equ "-file" set file=%%~fsA
if /I "!prev!" equ "-begin" set begin=%%~A
if /I "!prev!" equ "-end" set end=%%A
set prev=%%~A
)
endlocal & (
if "%file%" neq "" (set file=%file%)
if "%begin%" neq "" (set /a begin=%begin%)
if "%end%" neq "" (set /a end=%end%)
)
rem -----------------------------
rem --- invalid cases check -----
rem -----------------------------
if "%file%" EQU "" echo file not defined && exit /b 1
if not exist "%file%" echo file not exists && exit /b 2
if not defined begin if not defined end echo neither BEGIN line nor END line are defined && exit /b 3
rem --------------------------
rem -- function selection ----
rem --------------------------
if defined begin if %begin%0 LSS 0 for /F %%C in ('find /c /v "" ^<"%file%"') do set /a lines_count=%%C
if defined end if %end%0 LSS 0 if not defined lines_count for /F %%C in ('find /c /v "" ^<"%file%"') do set lines_count=%%C
rem -- begin only
if not defined begin if defined end if %end%0 GEQ 0 goto :end_only
if not defined begin if defined end if %end%0 LSS 0 (
set /a end=%lines_count%%end%+1
goto :end_only
)
rem -- end only
if not defined end if defined begin if %begin%0 GEQ 0 goto :begin_only
if not defined end if defined begin if %begin%0 LSS 0 (
set /a begin=%lines_count%%begin%+1
goto :begin_only
)
rem -- begin and end
if %begin%0 LSS 0 if %end%0 LSS 0 (
set /a begin=%lines_count%%begin%+1
set /a end=%lines_count%%end%+1
goto :begin_end
)
if %begin%0 LSS 0 if %end%0 GEQ 0 (
set /a begin=%lines_count%%begin%+1
goto :begin_end
)
if %begin%0 GEQ 0 if %end%0 LSS 0 (
set /a end=%lines_count%%end%+1
goto :begin_end
)
if %begin%0 GEQ 0 if %end%0 GEQ 0 (
goto :begin_end
)
goto :eof
rem -------------------------
rem ------ functions --------
rem -------------------------
rem --- single cases ---
:begin_only
setlocal enableDelayedExpansion
set counter=0
for /f "usebackq delims=" %%L in ("%file%") do (
set /a counter=!counter!+1
if !counter! GEQ %begin% (
setlocal disableDelayedExpansion
(echo(%%L)
endlocal
)
)
endlocal
goto :eof
:end_only
setlocal enableDelayedExpansion
set counter=0
for /f "usebackq delims=" %%L in ("%file%") do (
set /a counter=!counter!+1
if !counter! LEQ %end% (
setlocal disableDelayedExpansion
(echo(%%L)
endlocal
) else goto :break_eo
)
:break_eo
endlocal
goto :eof
rem ---- begin and end ---
:begin_end
setlocal enableDelayedExpansion
if %begin% GTR %end% goto :break_be
set counter=0
for /f "usebackq delims=" %%L in ("%file%") do (
set /a counter=!counter!+1
IF !counter! GEQ %begin% IF !counter! LEQ %end% (
setlocal disableDelayedExpansion
(echo(%%L)
endlocal
) else goto :break_be
)
:break_be
endlocal
goto :eof
rem ------------------
rem --- HELP ---------
rem ------------------
:help
echo(
echo %~n0 - dipsplays a lines of a file defined by -BEGIN and -END arguments passed to it
echo(
echo( USAGE:
echo(
echo %~n0 -file=file_to_process {-begin=begin_line ^| -end=end_line }
echo or
echo %~n0 -file file_to_process {-begin begin_line ^| -end end_line }
echo(
echo( if some of arguments BEGIN or END has a negative number it will start to count from the end of file
echo(
echo( http://ss64.org/viewtopic.php^?id^=1707
echo(
goto :eof
#12 17 Jul 2013 20:39
npocmaka
just a way with a less code to show the first lines of a file:
Code: Select all
@echo off
break>"%temp%\empty"
rem
rem fc "<some_file>" "%temp%\empty" /lb <numbers> /t | find /v "*****" | more +1
rem for /f "skip=3 eol=* delims=" %%L in ('fc "%temp%\empty" "<some_file>" /lb<lines_to_show> /t') do (echo(%%L)
rem
fc "%temp%\empty" "<some_file>" /lb <lines_to_show> /t |more +4 | findstr /B /E /V "*****"
rem and a line counter
for /f "skip=5 eol=* delims=: " %%N in ('fc %temp%\empty shiftt.bat /a /n') do (echo(%%N)