Tail \ Head

Microsoft Windows
Post Reply
User avatar
MigrationUser
Posts: 336
Joined: 2021-Jul-12, 1:37 pm
Contact:

Tail \ Head

Post by MigrationUser »

22 May 2013 06:46
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
Not good work so good - set's one additional new line at the end.And !s are not processed well.

Last edited by npocmaka (23 May 2013 13:08)

----------------------------

#2 22 May 2013 07:43
jeb


Hi npocmaka,
npocmaka wrote:

And !s are not processed well.
Disable delayed expansion and this problem is gone.

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
The main fault that I was not thought is that if the line starts with : it will be missed.

And the possibility of breaking parentheses context makes me sick :) .Prefer to use echo? or echo\ instead of echo(

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.
npocmaka wrote:

And the possibility of breaking parentheses context makes me sick :) .Prefer to use echo? or echo\ instead of echo(
No. echo( never breaks the parentheses context.
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
borrowed some code form Ranguna173 . Hope she/he does not mind whoever she/he is.

----------------------------

#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
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"
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.

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
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.
Confirmed fwiw. That's a bugger. Win 8 converts a tab at the start of a line into 8 spaces.

There are so many gotcha's in batch - I think that's why we like it. :D

----------------------------

#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
Last edited by npocmaka (23 May 2013 18:40)

----------------------------

#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)
Last edited by npocmaka (17 Jul 2013 22:42)
Post Reply