Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

SLICE

18 views
Skip to first unread message

Kulin Remailer

unread,
Sep 4, 2011, 6:33:58 PM9/4/11
to
Hello All!

I have of late, wherefore I know not, started writing little batch

programs. Below is a little something called slice.bat.

Hope you like it. Please don't be too hard on me. I'm new.

Will discuss further in a follow-up post. Sorry about posting

anonymously, btw. Just protecting myself from the spambots.

Contact me at:

john[DOT]oregan

[AT]gmail[DOT]com

bye for now,

John

PS: Many thanks to Timo Salmi, Rob van der Woude, Simon Sheppard, Jugado and

Frank Westlake.

---- slice.bat ----

@echo off & setlocal enableextensions disabledelayedexpansion

set code=0

if "%~1"=="" (echo:Usage: SLICE /B:x /E:y FILE

echo: Enter "SLICE /?" for additional help.

set code=1& goto _end)

:_cmdline

set seen=0

if "%~1"=="" (goto _main)

set arg=%~1

if "%arg%"=="/?" goto _usage

if /i "%arg:~0,3%"=="/b:" call :_checkno "%arg%" begin

if /i "%arg:~0,3%"=="/e:" call :_checkno "%arg%" end

if %seen%==0 if "%arg:~0,1%" neq "/" if exist "%arg%" (

set file=%arg%

set seen=1) else (echo:file "%~nx1" not found 1>&2 & set code=1)

if %seen%==1 set arg=

if %code%==1 goto _end

if "%arg%"=="" (shift& goto _cmdline

) else (echo:unknown command line switch or parameter: "%arg%" 1>&2

set code=1& goto _end)

:_main

if not defined begin echo:the "/b:" switch is required 1>&2

if not defined end echo:the "/e:" switch is required 1>&2

if not defined file (echo:no file found on command line 1>&2

set code=1& goto _end)

if %begin% neq 0 set /a begin-=1

if %end%==0 set /a end+=1

if %begin%==%end% set /a end+=1

if %begin% gtr %end% (

echo:value of "/b:" switch cannot exceed that of "/e:" 1>&2

set code=1& goto _end

)

set "options=tokens=* delims=0123456789"

if %begin% neq 0 set "options=skip=%begin% %options%"

(for /f "%options%" %%a in ('findstr /n ".*" "%file%"') do @(

echo%%a

for /f "tokens=*" %%x in ('set /a begin+=1') do @(

echo:%%x| findstr /b "%end%" > nul && exit)

set /a begin+=1 > nul

)) | more /e

set "code=0" & goto _end

:_usage

for /f "tokens=1 delims=:" %%f in ('findstr /nber "__HELP__" %~s0') do set helpline=%%f

more /e /c +%helpline% %~s0 & set code=0

:_end

set seen=

set arg=

set begin=

set end=

set file=

set options=

set helpline=

endlocal & exit /b %code%

:_checkno

set str=%~1

set sw=%str:~0,3%

set val=%str:~3%

if not defined val (echo:missing value for "%sw%" switch 1>&2

set code=1& goto _setvars)

echo:%val%| findstr /ber "0 [1-9][0-9]*" > nul ^

|| (echo:"%val%" is invalid value for "%sw%" switch 1>&2

set code=1& goto _setvars)

set %2=%val%

:_setvars

set seen=1& set str=& set sw=& set val=

goto :EOF

__HELP__

Sends a user-specified range of lines from a text file to standard output.

SLICE /B:x /E:y FILE

/B:x Begin displaying lines from line x in FILE.

/E:y End the display of lines from FILE at line y.

/? Display this message and exit.

The value of x must not exceed y. Lines are counted from 1. If a value of

0 is given, it will be incremented. Lines will be displayed from x to y,

inclusive. FILE must be a text file. Blank lines and "poison characters"

will be displayed correctly. The backspace character (Ctrl+H) may be

problematic, especially at the beginning of a line.


Todd Vargo

unread,
Sep 5, 2011, 1:33:18 AM9/5/11
to

"Kulin Remailer" <rema...@reece.net.au> wrote in message
news:BHWR5CSM407...@reece.net.au...

> Hello All!
>
>
>
> I have of late, wherefore I know not, started writing little batch
>
> programs. Below is a little something called slice.bat.
>
> Hope you like it. Please don't be too hard on me. I'm new.
>
>
>
> Will discuss further in a follow-up post. Sorry about posting
>
> anonymously, btw. Just protecting myself from the spambots.
>
> Contact me at:
>
>
>
> john[DOT]oregan
>
> [AT]gmail[DOT]com
>
>
>
> bye for now,
>
> John
>
>
>
>
>
> PS: Many thanks to Timo Salmi, Rob van der Woude, Simon Sheppard, Jugado
> and
>
> Frank Westlake.
>
>
>
> ---- slice.bat ----
>
> @echo off & setlocal enableextensions disabledelayedexpansion
>
> set code=0

<snip>


Nice work. Here is another way which you may find of interest.

::Slice.cmd


@echo off & setlocal enableextensions disabledelayedexpansion

if "%~3" equ "" (
echo.
echo Sends a user-specified range of lines from a text file to standard
output.
echo.
echo.
echo. %0 {begin} {end} FILE
echo.
echo.
echo. {begin} Begin displaying lines from line {begin} in FILE.
echo.
echo {end} End the display of lines from FILE at line {end}.
echo.
echo. FILE Filespec of file to process.
echo.
echo.
echo. Lines begin at 1. The value of {begin} must not exceed {end}.
echo. Lines will be displayed from {begin} to {end} inclusive.
echo. FILE must be a text file. Blank lines and "poison characters"
echo. will be displayed correctly. The backspace character ^(Ctrl+H^)
echo. may be problematic, especially at the beginning of a line.
goto :eof
)

:Validate {begin}
echo:%~1| findstr /ber "0 [1-9][0-9]*" > nul ^
|| (echo: "%~1" is invalid for "{begin}" value 1>&2
call %0 & goto :eof)
if %1 equ 0 (echo: "%~1" is invalid value for "{begin}" value 1>&2
%0)

:Validate {end}
echo:%~2| findstr /ber "0 [1-9][0-9]*" > nul ^
|| (echo: "%~2" is invalid for "{end}" value 1>&2
%0)

:Verify {begin} is less than or equal to {end}
if %1 gtr %2 (
echo {begin} "%1" must be less than or equal to {end} "%2"
%0)

:Check if FILE exists
if not exist %3 (
echo %3 does not exist
%0)

set /a "begin=%1-1"


set "options=tokens=* delims=0123456789"
if %begin% neq 0 set "options=skip=%begin% %options%"

(for /f "%options%" %%a in ('findstr /n ".*" "%3"') do @(


echo%%a
for /f "tokens=*" %%x in ('set /a begin+=1') do @(

echo:%%x| findstr /b "%2" > nul && exit)

Message has been deleted

foxidrive

unread,
Sep 7, 2011, 6:06:20 PM9/7/11
to
On 5/09/2011 08:33, Kulin Remailer wrote:
> Hello All!
>
> I have of late, wherefore I know not, started writing little batch
> programs. Below is a little something called slice.bat.
> Hope you like it. Please don't be too hard on me. I'm new.

Welcome Kulin. You're not new to batch files by the look of it.


I stole a leaf from the book of Tom Lavedas to create the following.


file.bat start# end# <"file in.txt" >"file out.txt"


@echo off
(echo c = 0
echo do until wsh.stdin.atendofstream
echo c = c + 1
echo out = wsh.stdin.readline
echo if c ^> %1 - 1 and c ^< %2 + 1 then _
echo wsh.stdout.writeline out
echo loop
) > %temp%.\tmp.vbs
cscript //nologo %temp%.\tmp.vbs
del %temp%.\tmp.vbs

There isn't a lot of error checking (if you count zero as some) but it does the job. :)

--
Regards,
Mic

Tom Lavedas

unread,
Sep 8, 2011, 8:14:07 AM9/8/11
to

One problem I spotted with this method is that there MUST BE a space
after the end# argument or it is interpreted with the redirection
character as a numbered pipe (even though numbered pipes are not
really supported at the command prompt beyond 2).

Also, since you introduced the hybrid approach, I couldn't help but
tweak it ...

@echo off
(echo for i=2 to %1 : wsh.stdin.skipline : Next
echo for i=%1 to %2
echo if not wsh.stdin.atendofstream then _
echo wsh.stdout.writeline wsh.stdin.readline
echo next


) > %temp%.\tmp.vbs
cscript //nologo %temp%.\tmp.vbs
del %temp%.\tmp.vbs

_________________________
Tom Lavedas

Tom Lavedas

unread,
Sep 8, 2011, 9:08:47 AM9/8/11
to
> Tom Lavedas- Hide quoted text -
>
> - Show quoted text -

A tweak of the tweak ...

@echo off
(echo for i=2 to %1 : wsh.stdin.skipline : Next
echo for i=%1 to %2
echo if not wsh.stdin.atendofstream then wsh.quit i-1
echo wsh.stdout.writeline wsh.stdin.readline
echo next
) > %temp%.\tmp.vbs
cscript //nologo %temp%.\tmp.vbs
del %temp%.\tmp.vbs

An errorlevel equal to the number of the last line is returned, if the
end of the file is exceeded. A start# past the EOF still throws an
error.
_____________________________
Tom Lavedas

foxidrive

unread,
Sep 8, 2011, 11:41:11 AM9/8/11
to
Thanks for your comments and tweaks, Tom.


--
Regards,
Mic

Simon

unread,
Sep 8, 2011, 1:40:46 PM9/8/11
to
Here's another way, this is similar to Todd's version but this one
seems to run a bit faster.
No error checking and it could use a more robust DeQuote routine but
its a start

:: slice.cmd
@echo off
Setlocal EnableDelayedExpansion
:: usage: SLICE.CMD start# stop# "filename.txt"

Set /a "_start=%1-1"
Set /a "_lines=%2-%1"

FOR /F "tokens=1,* delims=:" %%G IN ('more +!_start! %3 ^|findstr/nr
".*"') DO (
call :s_echo %%G "%%H")
GOTO :eof

:s_echo
IF /I %1 GTR !_lines! GOTO :eof

:: Echo empty lines
IF [%2]==[""] Echo. &GOTO :eof

:: Remove quotes
SET _line=###%2###
SET _line=%_line:"###=%
SET _line=%_line:###"=%
SET _line=%_line:###=%

:: Echo this line
ECHO %_line%
GOTO :eof

-
Simon Sheppard

Tom Lavedas

unread,
Sep 8, 2011, 2:09:00 PM9/8/11
to
Try your version with this test file ...

dump.txt
]]]]]1234 []
<nul echo test
::
%1234% ^| cmd <nul
1234 !1234!

for /f "tokens=1*delims=]" %%a in (
'find /v /n "" ^< %1') do (echo.%%b)
name.txt
[1]Comedy | USA =| "English" | 1950 % a % !%!%! > a

%%CAST Dean Martin, Jerry Lewis
===[End file]===

You might be surprised by the results.

BTW, the simplest solution to removing quotes is the %~2 approach.
From the command line help for FOR ...

You can now use the following optional syntax:

%~I - expands %I removing any surrounding quotes (")

There is another help that expands that to the replacable (numbered)
command line arguments, but I can't remember which one it is right
now.
____________________________
Tom Lavedas

Simon Sheppard

unread,
Sep 8, 2011, 3:39:26 PM9/8/11
to
On 2011-09-08 19:09:00 +0100, Tom Lavedas <tglb...@verizon.net> said:

>>
>
> Try your version with this test file ...
>
> dump.txt
> ]]]]]1234 []
> <nul echo test
> ::
> %1234% ^| cmd <nul
> 1234 !1234!
>
> for /f "tokens=1*delims=]" %%a in (
> 'find /v /n "" ^< %1') do (echo.%%b)
> name.txt
> [1]Comedy | USA =| "English" | 1950 % a % !%!%! > a
>
> %%CAST Dean Martin, Jerry Lewis
> ===[End file]==
>
> You might be surprised by the results.

Yes that breaks it, needs more work!

Nomen Nescio

unread,
Sep 8, 2011, 8:20:40 PM9/8/11
to
Hello Again,

Thanks for your feedback, Todd! Your script-writing style doesn't beat
around the bush. I tend to overdo the verifying and error checking.
Programmers can't assume the people who are going to use their scripts are
experts, but I shouldn't treat them like morons, either. I'll try to keep
that in mind.

And Carlos! I love your voodoo variant. I've no idea how it works. I
never knew you could use SET /A to initialise multiple variables. Extremely
useful. Your program seems to be storing each line of the source file in a
variable. But I'm not sure how it's being read in. And what if you had to
read in thousands of lines? Wouldn't you run out of environment space?

Lastly, in the FREAD block, you call _FREAD with the arguments - and
"%~2" (the source file) but you don't refer to them in the _FREAD block.
And what is - supposed to do, anyway? And the SET /P command seems to set
the variable to nothing at all... until it's ECHOed in the fread block and
out pops the corresponding line from the input file! It's the dark arts, I
tell ya!

Thanks to Mic and Tom for their VBS versions. I keep putting it off, but
sooner or later I'll have to learn VBS. Btw, is there any way to make the
CSCRIPT command accept standard input instead of a file?

Anyways, in my original program, I wanted the output from the FOR loop
to be piped to MORE in one go so I enclosed it in parentheses. This is when
things became a little surreal. The FOR loop's block started behaving like
a command prompt. I had to put an @ in front of the opening parenthesis. I
had to say SET /A begin+=1 > NUL instead of SET /A begin+=1 and I couldn't
jump out of the loop. Worse again, SET /A begin+=1 would *say* it had
incremented the variable, but it would still have its old value at the
next iteration of the loop.

That's when I stumbled upon the solution of including the instruction
SET /A begin+=1 twice. I call it the sympathetic increment. I don't know
how it works, just that the program doesn't work without it. And I was
able to jump out of the loop by comparing begin's incremented value to end
using FINDSTR and EXITing if there was a match.

Meanwhile, I was trying to use FINDSTR /N to list a range of lines
(including blanks) in the "head" of the FOR loop. But how to get rid of
the numbers? Use a colon as the delimiter? Close, but no cigar. What if a
line began with a colon? The FOR loop would consume it. Not quite verbatim
output. Then Jugado put me onto the idea of using 0-9 as the DELIMS in a
FOR loop. That got rid of the numbers from FINDSTR /N's output, but how to
get rid of the colon? And that's when I realised that I didn't have to. I
remembered reading on Simon Sheppard's ECHO page something about ECHO:
being more efficient than ECHO. so I tried ECHO%%a instead of ECHO %%a in
the FOR loop and it worked!

In the light of all your suggestions, my original needs some tweaking.
I'll post a Dropbox link when it's finished. Thanks again to everyone for
replying. You can contact me at:

I'm_HERE

unread,
Sep 9, 2011, 10:06:18 AM9/9/11
to
# for fun, with powershell

-----------------8<-----------------

$file="c:\slice.txt"
$start,$end=2,5
(gc $file)[($start-1)..$end]

-----------------8<-----------------

I'm_HERE

unread,
Sep 10, 2011, 1:35:25 AM9/10/11
to
another method:



-----------------8<-----------------
@echo off
Setlocal EnableDelayedExpansion

:: Usage: code.cmd <int>start <int>end filename

set "file=%~3"
set start=%1
set end=%2

for /f "tokens=1* delims=:" %%a In ('
findstr /N $ %file%') do (set lines=%%a&set "#%%a=#%%b"
)
for /l %%i in (1 1 %lines%) do (
set "ln=!#%%i!"
if %%i geq %START% echo(!ln:~1!
if %%i geq %END% (endlocal&goto:break)
)
:break
pause

-----------------8<-----------------

foxidrive

unread,
Sep 10, 2011, 7:51:51 AM9/10/11
to

You have to move the setlocal lower down otherwise lines with ! in it are broken.
It also has an issue with lines starting with :

@echo off

:: Usage: code.cmd <int>start <int>end filename

set "file=%~3"
set start=%1
set end=%2

for /f "tokens=1* delims=:" %%a In ('
findstr /N $ %file%') do (set lines=%%a&set "#%%a=#%%b"
)

Setlocal EnableDelayedExpansion

for /l %%i in (1 1 %lines%) do (
set "ln=!#%%i!"
if %%i geq %START% echo(!ln:~1!
if %%i geq %END% (endlocal&goto:break)
)
:break
pause


--
Regards,
Mic

Message has been deleted

Tom Lavedas

unread,
Sep 12, 2011, 5:23:32 PM9/12/11
to
On Sep 12, 12:49 pm, carlos <cmonti...@gmail.com> wrote:
> I improve my previous code (I deleted the post). It had the problem
> that if you specify a greater number of lines that contains the file,
> blank lines are printed.
> The method published using findstr has the problem that if a file does
> not end with CRLF, the the last line is not considered, also lines
> that started with : are printed without initials : characters.
>
>  With the technique of reading the file with set / p and find the line
> numbers with findstr I solved the problem. Maybe the code can be
> improved.
> I check the number of lines of the file, starting variable in 1
> because any file have 1 line, then with findstr I add the number to
> the var, this is for check files that not end with crlf, if file have
> 1 line and not end with crlf, the for /f catch none, but anyways the
> var is 1. Now I send the file how input for set /p for dinamically
> read the lines, not all again, only to the neccesary line.
>
> @echo off
> :: Usage: slice.cmd <int>start <int>end filename
> Call :slice "%~1" "%~2" "%~3"
> Goto :Eof
>
> :slice
> SetLocal EnableDelayedExpansion
> Set "f=%~f3"
> Set /a "_n=0,_fb=0,_fe=0,_l=1"
> Set /a "_fb+=%~1,_fe+=%~2" 2>Nul && If Exist "!f!" (
> For /f "delims=:" %%e in ('Findstr.exe /n $ "!f!"'
> ) do Set /a "_l=%%e+1"
> If !_fe! Gtr !_l! Set "_fe=!_l!"
> Call :_slice < "!f!"
> )
> EndLocal
> Goto :Eof
> :_slice
> Set /a "_n+=1"
> Set /p "_fl="
> If %_n% Geq %_fb% (Echo.!_fl!)
> If %_n% Geq %_fe% Goto :Eof
> Goto :_slice

Interesting, but I had a problem with this implementation - it output
the previous line a second time when the current line was blank. The
simple solution was to clear the _fl variable after it was echoed.
However, please forgive me - I couldn't leave well enough alone, so I
began tweaking and ended up with this ...

@echo off
:: Usage: slice.cmd <int>start <int>end filename
Call :slice "%~1" "%~2" "%~f3"
Goto :Eof

:slice
SetLocal
Set /a "_n=0, _fb=%~1, _fe=%~2" 2>Nul
If Exist %3 (
For /f %%e in ('Find /c /v "" ^< %3'
) do If %_fe% Gtr %%e Set "_fe=%%e"
SetLocal EnableDelayedExpansion
Call :_slice < %3
) else (echo.File %3 not found.)
Goto :Eof

:_slice
Set /a "_n+=1"
Set /p "_fl="
If %_n% Geq %_fb% (Echo.!_fl!)
set "_fl="
If %_n% LSS %_fe% Goto :_slice

I might do more, but I've done enough already.
___________________________
Tom Lavedas

I'm_HERE

unread,
Sep 12, 2011, 6:02:01 PM9/12/11
to
another variant with new technic:

-----------------8<-----------------
@echo off
:: Usage: slice.cmd <int>start <int>end filename

Setlocal EnableDelayedExpansion
for /f %%i in ('find /n /v "" ^< %3') do set/A cnt+=1
(for /l %%r in ( 1 1 %cnt% ) do (
set line=
set /p line=
if %%r GEQ %1 echo(!line!
if %%r GEQ %2 (Endlocal&goto:break)
)) < %3
:break
goto :EOF

-----------------8<-----------------
Message has been deleted

carlos

unread,
Sep 12, 2011, 10:42:23 PM9/12/11
to
Sorry, is needed remove the quotes from arguments. Else the code fails
with call with the arguments in quotes.
This is my final version:

@Echo off
:: Usage: slice.cmd <int>start <int>end filename
Setlocal EnableDelayedExpansion
Set "f=%~f3"&Set/a#=1&For /f "delims=:" %%# in (
'Findstr.exe /n $ "!f!" 2^>Nul') do Set/a#=1+%%#
(For /l %%# in (1 1 %#%) do (Set "#="&Set/p"#="
If %%# Geq %~1 Echo:!#!&If %%# Geq %~2 Goto:Eof))<"!f!"
EndLocal&Goto:Eof

I'm_HERE

unread,
Sep 13, 2011, 12:57:30 AM9/13/11
to
another variant:

-----------------8<-----------------untested.bat-------
@Echo off
:: Usage: slice.cmd <int/Exclusive>start <int/Exclusive>end filename

set /A start=%1
set /A end=%2
set flg=

For /f "tokens=1* delims=:" %%a in ('Findstr.exe /n $ "%3"') do (
echo(%%a:|findstr /b "%end%:" >nul && set flg=
if defined flg echo(%%b
echo(%%a:|findstr /b "%start%:" >nul && set flg=flg
)
goto:eof

-----------------8<------------------------------

Tom Lavedas

unread,
Sep 13, 2011, 9:58:56 AM9/13/11
to
This has the problem with lines that begin with colon.

Here is a reprint of the test file that has been used before for such
procedures ...

dump.txt
]]]]]1234 []
<nul echo test
::
%1234% ^| cmd <nul
1234 !1234!

for /f "tokens=1*delims=]" %%a in (
'find /v /n "" ^< %1') do (echo.%%b)
name.txt
[1]Comedy | USA =| "English" | 1950 % a % !%!%! > a

%%CAST Dean Martin, Jerry Lewis
===[End file]===

It is best to mod it after cutting and pasting so that it ends at the
last equal sign (without a newline on the last line).

I believe this modification of I'm Here's offering can do the job
(though the hybrid script is simpler, I think).

@echo off
:: Usage: slice.cmd <int>start <int>end filename

if exist %3 (
Setlocal EnableDelayedExpansion
%4 for /f %%C in ('find /c /v "" ^< %3') do (
%4 if %2 GTR %%C %0 %1 %%C %3 ::)
(for /l %%r in ( 1 1 %2 ) do (
set line=
set /p line=
if %%r GEQ %1 echo(!line!
)) < %3
) else (echo.File %3 not found.)
echo.

Note that FIND does COUNT and number lines correctly - even the blank
ones. The problem is with the FOR that does not process its DO clause
for an empty line.
____________________________
Tom Lavedas

carlos

unread,
Sep 13, 2011, 4:15:59 PM9/13/11
to
On 13 sep, 10:58, Tom Lavedas <tglba...@verizon.net> wrote:
> I believe this modification of I'm Here's offering can do the job
> (though the hybrid script is simpler, I think).

> Note that FIND does COUNT and number lines correctly - even the blank
> ones. The problem is with the FOR that does not process its DO clause
> for an empty line.
>
The hybrid script fails if you specify a end line greather than the
file have.
The find file not count the number lines correctly. For example a file
with:
crlf
crlf

say 0
and a file with:

crlf
any chr

say 2

I publish my final and stable code in:
http://carlitossoft.110mb.com/batch/#slice

Tom Lavedas

unread,
Sep 13, 2011, 4:53:32 PM9/13/11
to
As far as I'm concerned the second example has two lines. The lack of
a CRLF line termination does not make the second line a 'non-line'.
And the first example seems to me to be so trivial, that I can almost
overlook it. I guess the solution is to use the TYPE formulation to
fix it ...

type filename | find /v /c ""

As far as the hybrid, I stated that it throws an error. I just didn't
take the time to fix it, though it is pretty trivial to do ...

@echo off
(echo on error resume next
echo for i=2 to %1 : wsh.stdin.skipline : Next
echo for i=%1 to %2
echo if wsh.stdin.atendofstream then wsh.quit i-1
echo wsh.stdout.writeline wsh.stdin.readline
echo next
) > %temp%.\tmp.vbs
cscript //nologo %temp%.\tmp.vbs
if errorlevel 1 echo File ends at line %errorlevel%
del %temp%.\tmp.vbs

My corporate security keeps me from visiting the page you cite, so I
can't comment on your effort, though I'm expect it is fine.

Here is my latest effort, keying off of I'm_HERE's use of the set /p
to read one line at a time and a FOR/L to count the lines being
displayed ...

:: MySlice start# end# filename
@echo off
setlocal enabledelayedexpansion
%4 if not exist %3 (echo.File %3 not found.&exit /b 1)
%4 for /f %%C in ('type %3 ^| find /c /v ""') do (
%4 if %2 GTR %%C %0 %1 %%C %3 ::)
%5 for /l %%L in (%1 1 %2) do (set /a N=%%L-1
%5 more +!N! %3 | call %0 1 2 3 :: :: %%L)
%5 exit /b 0
set /p "Txt=%6{TAB}"
echo.!Txt!

Note that the %6{TAB} is just there for demonstration purposes and can
be removed. Replace the {TAB} string with the tab character to test.

This is an interesting approach in that it is easily adjusted to
reverse the file, last line to first line ...

:: Reverse start# end# filename
@echo off
setlocal enabledelayedexpansion
%4 if not exist %3 (echo.File %3 not found.&exit /b 1)
%4 for /f %%C in ('type %3 ^| find /c /v ""') do (
%4 if %2 GTR %%C %0 %1 %%C %3 ::)
%5 for /l %%L in (%2 -1 %1) do (set /a N=%%L-1
%5 more +!N! %3 | call %0 1 2 3 ::4 ::5 %%L)
%5 exit /b 0
set /p "Txt=%6{TAB}"
echo.!Txt!

Or select the last N lines ...

:: LastNLines fn [NLines]
@echo off
setlocal enabledelayedexpansion
%3 if not exist %1 (echo.File %1 not found.&exit /b 1)
%3 if [%2]==[] %0 %1 1
%3 for /f %%C in ('find /c /v "" ^< %1') do (
%3 if %2 GTR %%C (%0 %1 %%C) else (
%3 for /l %%L in (%2 -1 1) do (set /a N=%%C-%%L
%3 more +!N! %1 | call %0 1 2 ::2)))
%3 exit /b 0
set /p "Txt="
echo.!Txt!

An optional count can be added to output the last N lines.

Or with a few changes the first N lines ...

:: FirstNLines fn [NLines]
@echo off
setlocal enabledelayedexpansion
%3 if not exist %1 (echo.File %1 not found.&exit /b 1)
%3 if [%2]==[] %0 %1 1
%3 for /f %%C in ('type %1 ^| find /c /v ""') do (
%3 if %2 GTR %%C (%0 %1 %%C) else (
%3 for /l %%L in (1 1 %2) do (set /a N=%%L-1
%3 more +!N! %1 | call %0 1 2 ::2)))
%3 exit /b 0
set /p "Txt="
echo[!Txt!

Leaving the second argument blank, displays just the first line.
________________________
Tom Lavedas

carlos

unread,
Sep 14, 2011, 7:28:57 AM9/14/11
to
On 13 sep, 17:53, Tom Lavedas <tglba...@verizon.net> wrote:
> My corporate security keeps me from visiting the page you cite, so I
> can't comment on your effort, though I'm expect it is fine.

I don't know what dns server you have or antivirus proxy.
Anyways is a false positive because the web only have plain html. I
unknow the reason for this.
I use mcafee site advisory and I can access to the web without
problems. In my school that have other security proxies, I can access
without problems.
All the utilities are open source, (except the prototype of batch
compiler), and the executables are all scanned with more than 40
antivirus, and all is clear.

John O'Regan

unread,
Sep 18, 2011, 4:39:29 PM9/18/11
to
(Third time trying to post this reply. My anonymous remailer stopped
working. I'd complain...
but who would I send the email to? Decided to use an old address
that's already burnt.
I'll be posting much more often now. Might as well be hung for a
sheep as a lamb!)

Me Again!

Wow! Wasn't expecting such a huge response to my little SLICE.
Thanks to
everyone who replied. But it seems the gurus on this newsgroup like to
let
their code do the talking. I'm still confused about a few things...

Someone please explain how CALL :SBRTN - "%file%" works. what does
the
"-" mean? And in the SBRTN it's sent to, how is SET /P "line=" able to
pluck a line from the input file out of thin air?

Lastly, why does Tom Lavedas start every line of his solution with
%4,
%5 or %6 when SLICE only takes three arguments? What function do %4
and
friends perform? Someone please explain,

imploringly,
John

Tom Lavedas

unread,
Sep 19, 2011, 8:43:32 AM9/19/11
to
On Sep 18, 4:39 pm, "John O'Regan" <j.ore...@cs.ucc.ie> wrote:
>
>   Lastly, why does Tom Lavedas start every line of his solution with
> %4, %5 or %6 when SLICE only takes three arguments? What function do
> %4 and friends perform? Someone please explain,
>
> imploringly,
> John

It's not every line - two have no prefixed arguments ;-)

The approach I used re-enters the same batch procedure several times.
Each time it re-starts the batch, the procedure passes revised
information to control which line(s) get executed. The extra arguments
are either blank (execute that line) or double colons (undocumented
REM equivalents to skip that line). I did it that way to position the
SET/P statements to receive the piped or redirected input in the
proper way after checking the proper values for the input arguments.

I guess I could have used CALL :SomeSUB statements, but the re-entrant
approach takes fewer lines of code. The drawback being the logic is
harder to follow. However, once understood, I find it to be a very
powerful batch programming concept.

HTH,
___________________________
Tom Lavedas

Frank P. Westlake

unread,
Sep 21, 2011, 9:17:56 AM9/21/11
to
"John O'Regan" news:33bd6fbe-10fa-4219...@et6g2000vbb.googlegroups.com...

> Someone please explain how CALL :SBRTN - "%file%" works. what does
> the "-" mean?

It looks like you are referring to a specific subroutine named "SBRTN" which I have not seen, but no one else has answered so I'll
answer in general. The hyphen is something that particular subroutine is aware of, it could mean anything. Perhaps the author is
using it to mean "skip this parameter", or "take input from STDIN".

> And in the SBRTN it's sent to, how is SET /P "line=" able to
> pluck a line from the input file out of thin air?

SET /P expects input from STANDARD INPUT -- a human banging on a keyboard. A script can override that STANDARD INPUT by redirecting
another device to it ( < file), or by piping the output of another command into it (COMMAND | SET/P "line="). The result is the
same. SET /P does not handle the file at all, it has only an input stream handed to it by the system. Apparenty CMD buffers the
input stream and gives SET/P only as much as it wants. Normally if a program does not read the entire input stream before the
program exits then whatever was not read is lost, so this is an unexpected benefit of CMD.

Frank


John O'Regan

unread,
Sep 24, 2011, 5:37:16 PM9/24/11
to
Hi Guys!

Thanks again for the huge response to my SLICE. I'm still digesting
all the answers. That's why it's taken me so long to respond.

Firstly, thanks to Tom Lavedas for explaining his re-entrant code
technique. It all made perfect sense once he spelt it out for me.
And apologies to Frank Westlake. In one of his earlier versions,
Carlos used the line:

Call :_Slice < "!F!"

I got LESS and DASH mixed up. Sorry about that. Now I get it. It's
redirection. It never occurred to me that you could redirect input to
a subroutine. And I saw someone do the same for a FOR /L loop. Much
food for thought.

Just one last thing. Did we reach a consensus on which was the
"best" version? Best in terms of either efficiency or robustness,

bye for now,
John
Message has been deleted

carlos

unread,
Sep 30, 2011, 9:52:44 AM9/30/11
to
On 29 sep, 23:00, carlos <cmonti...@gmail.com> wrote:
> On 24 sep, 17:37, "John O'Regan" <j.ore...@cs.ucc.ie> wrote:
>
> >   Just one last thing.  Did we reach a consensus on which was the
> > "best" version?  Best in terms of either efficiency or robustness,
>
> I write a new version, and this is a tiny seconds more speedy than my
> old version (tested with timethis.exe).
>
> @Echo off
> :: Usage: slice.cmd filename [<int>start] [<int>end]
> :: Note: if end is 0 then prints until the end of file
> Setlocal EnableDelayedExpansion
> Set "f=%~f1"&Set/a"b=%~2,e=%~3,#=0" 2>Nul
> If !b! Leq 0 Set "b=1"
> If !e! Leq 0 Set "e=2147483647"
> For /f "delims=" %%$ in (
> '^(Type "!f!"^&Echo:^)^|Findstr.exe/n "^^"') do (
> Set/a"#=#+1"&Set "$=%%$"&Set "$=!$:*:=!"
> If !#! Geq %b% Echo:!$!&If !#! Geq %e% Goto:Eof)
> EndLocal&Goto:Eof

Errata: This line:
If !#! Geq %b% Echo:!$!&If !#! Geq %e% Goto:Eof)
could be:
If !#! Geq %b% Echo:!$!&If !#! Geq %e% EndLocal&Goto:Eof)

Then, finaly the code is:

@Echo off
:: Usage: slice.cmd filename [<int>start] [<int>end]
:: Note: if end is 0 then prints until the end of file
Setlocal EnableDelayedExpansion
Set "f=%~f1"&Set/a"b=%~2,e=%~3,#=0" 2>Nul
If !b! Leq 0 Set "b=1"
If !e! Leq 0 Set "e=2147483647"
For /f "delims=" %%$ in (
'^(Type "!f!"^&Echo:^)^|Findstr.exe/n "^^"') do (
Set/a"#=#+1"&Set "$=%%$"&Set "$=!$:*:=!"
If !#! Geq %b% Echo:!$!&If !#! Geq %e% EndLocal&Goto:Eof)
EndLocal&Goto:Eof
0 new messages