This answer might be more of academic value, but I could not resist to give it a try using the findstr
command that is capable of searching beyond line-breaks, which I intend to use for retrieving all but the last line first and the last line alone later.
The tricky part was to find a way to work around the problem that the search character .
unexpectedly matches the end-of-file as recorded in this post. I would expect the following code to match the last line but it fails (the string !_LF!!_CR!*!_LF!
matches lines preceding empty ones as there are two consecutive line-breaks, and the string !_LF!.
should match lines preceding non-empty ones, excluding the last one as there is either no line-break at all or such is not followed by anything, but this fails):
rem /* Delayed expansion is enabled, the variables `_LF` and `_CR`
rem are set to line-feed and carriage-return characters, resp.: */
findstr /V "!_LF!!_CR!*!_LF! !_LF!." "test.txt"
Therefore, I had to use a way around that, unfortunately having to use multiple findstr
commands, each of which reading the file on its own:
rem /* Test for trailing line-break using `$`, which anchors to carriage-return;
rem due to this, Unix-style text files are not supported by this method: */
> nul findstr /V "$" "test.txt" && (
rem // There is no trailing line-break, so `$` does not match the last line:
findstr "$" "test.txt"
) || (
rem /* There is a trailing line-break, so return all lines that precede two line-breaks
rem with something (except line-breaks since `.` does not match such) in between: */
findstr "!_LF!.*!_CR!!_LF!" "test.txt"
)
This is the full approach:
@echo off
setlocal EnableExtensions DisableDelayedExpansion
rem // Define constants here:
set "_FILE=.\test.txt" & rem // (path to target file)
(set ^"_LF=^
%= blank line =%
^") & rem // (this gathers a line-feed character)
rem // Gather a carriage-return character:
for /F %%Z in ('copy /Z "%ComSpec%" nul') do set "_CR=%%Z"
rem // Iterate through lines of text line by line:
for /F delims^=^ eol^= %%L in ('
rem/ First test for final line-break, then do specific search: ^
^& ^> nul findstr /V "$" "%_FILE%" ^
^&^& ^(findstr "$" "%_FILE%"^) ^
^|^| ^(cmd /V /C findstr "!_LF!.*!_CR!!_LF!" "!_FILE!"^)
') do (
rem /* Here all but the last lines are enumerated, which are then output
rem with a comma `,` appended; note that empty lines are ignored: */
echo(%%L,
)
rem // Here the last line is returned, independent from final line-break:
setlocal EnableDelayedExpansion
findstr /V "$" "!_FILE!" || findstr /V "!_LF!.*!_CR!!_LF!" "!_FILE!"
endlocal
endlocal
exit /B