0

I have a directory with nany text files, each containing an URL. I want to write each URL including a new line character to a text file. Therefore I created two batch files:

job.bat:

@echo off
forfiles /m *.m3u /c "cmd /c output.bat @file"

output.bat:

@echo off
type %1 >> urls.txt
echo. >> urls.txt

When I run job.bat all URLs are written to the text file.

But there is one problem: At the end of the text file there will be a new line at the end of the text file, even if no further line will follow. What can I do to remove the new line character at the end of urls.txt?

urls.txt should look like this: urls.txt

That's how job2.bat looks like: job2bat

I'm not able to insert a screenshot of urls.txt, since it needs to be scrolled. But I can tell you, that it contains all URLS, one after another without being seperated by any space or new line character.

The exact .m3u files can be found on a subpage of the homepage of a German radio station (ending with .m3u). Therefore I do not include any screenshot of a m3u file.

4

3 回答 3

1

If you have just a few files, (limited by the string length of the urls with regards maximum size of the variable environment), and your urls do not contain ! characters, (which would be deleted), you may get away with something like this:

@Echo Off & SetLocal EnableExtensions EnableDelayedExpansion
For /F %%G In ('Copy /Z "%~f0" NUL') Do Set "cr=%%G" & (Set lf=^
% 0x0A %
)
Set "fl=" & For /F Delims^=^ EOL^= %%G In ('Type *.m3u') Do If Not Defined fl (
    Set "fl=%%G") Else Set "fl=!fl! %%G"
If Defined fl Set /P "=%fl: =!cr!!lf!%" 0<NUL 1> "urls.txt"

If your files do not contain line terminators or line endings, which I've determined, seems to be consistent, you could just replace a different character or sequence of characters instead:

@Echo Off & SetLocal EnableExtensions EnableDelayedExpansion
For /F %%G In ('Copy /Z "%~f0" NUL') Do Set "cr=%%G" & (Set lf=^
% 0x0A %
)
Set "fl=" & For /F Delims^=^ EOL^= %%G In ('Type *.m3u') Do Set "fl=%%G"
If Defined fl Set /P "=%fl:3http:=3!cr!!lf!http:%" 0<NUL 1> "urls.txt"
于 2021-05-19T19:28:13.313 回答
1

For the sake of testing I am just using 3 urls each in a separate m3u file.

Take the following pseudo compiled code and save it as a .bat file. Place the bat file in the same folder as the m3u files.

@echo off&(if defined @lo@ goto ¡)&setlocal disableDelayedExpansion&for /f "delims=:. tokens=2" %%A in ('chcp') do set "@chcp@=chcp %%A>nul"&chcp 708>nul&set ^"@args@=%*"
set "@lo@= !#$&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~""
set "@hi@=%=%¡%=%¢%=%¤%=%¥%=%§%=%¨%=%©%=%ª%=%«%=%¬%=%­%=%®%=%¯%=%°%=%±%=%²%=%³%=%´%=%µ%=%¶%=%·%=%¸%=%¹%=%º%=%»%=%¼%=%½%=%¾%=%¿%=%À%=%Á%=%Â%=%Ã%=%Ä%=%Å%=%Æ%=%Ç%=%È%=%É%=%Ê%=%Ë%=%Ì%=%Í%=%Î%=%Ï%=%Ð%=%Ñ%=%Ò%=%Ó%=%Ô%=%Õ%=%Ö%=%×%=%Ø%=%Ù%=%Ú%=%Û%=%Ü%=%Ý%=%Þ%=%ß%=%à%=%á%=%â%=%ã%=%ä%=%å%=%æ%=%ç%=%è%=%é%=%ê%=%ë%=%ì%=%í%=%î%=%ï%=%ð%=%ñ%=%ò%=%ó%=%ô%=%õ%=%ö%=%÷%=%ø%=%ù%=%ú%=%û%=%ü%=%ý%=%þ%=%ÿ%=%£%=%"
(setlocal enableDelayedExpansion&for /l %%N in (0 1 93) do set "!@hi@:~%%N,1!=!@lo@:~%%N,1!")&cmd /c ^""%~f0" !@args@!"
%@chcp@%&exit /b
:¡
%Á%%æ%%ä%%é%%ð%%¡%%ð%%ç%%ç%
%ô%%æ%%õ%%í%%ð%%ä%%â%%í%%¡%%æ%%ï%%â%%ã%%í%%æ%%å%%æ%%í%%â%%ú%%æ%%å%%æ%%ù%%ñ%%â%%ï%%ô%%ê%%ð%%ï%
%ô%%æ%%õ%%¡%%£%%í%%ê%%ï%%æ%%¾%%£%
%©%
    %ç%%ð%%ó%%¡%%%%Ê%%¡%%ê%%ï%%¡%%©%%«%%¯%%î%%´%%ö%%ª%%¡%%å%%ð%%¡%%©%
        %ç%%ð%%ó%%¡%%°%%Ç%%¡%%£%%ö%%ô%%æ%%ã%%â%%ä%%ì%%ò%%¡%%å%%æ%%í%%ê%%î%%ô%%¾%%£%%¡%%%%Ë%%¡%%ê%%ï%%¡%%©%%£%%%%ÿ%%Ê%%£%%ª%%¡%%å%%ð%%¡%%©%
            %Ê%%Ç%%¡%%Å%%Æ%%Ç%%Ê%%Ï%%Æ%%Å%%¡%%í%%ê%%ï%%æ%%¡%%æ%%ä%%é%%ð%%¡%%¢%%í%%ê%%ï%%æ%%¢%
            %ô%%æ%%õ%%¡%%£%%í%%ê%%ï%%æ%%¾%%%%ÿ%%Ë%%£%
        %ª%
    %ª%
    %ô%%æ%%õ%%¡%%°%%ñ%%¡%%£%%¯%%¾%%¢%%í%%ê%%ï%%æ%%¢%%£%%½%%Ï%%Ö%%Í%
%ª%%¿%%ö%%ó%%í%%ô%%¯%%õ%%ù%%õ%

You should get the following output.

Notepad plus capture

Note: that is just a typo on my part with the last link.

于 2021-05-19T21:36:50.770 回答
1

Removing the very last line-break in a pure is not quite trivial, not only because there are several limitations that come into account (let us at this point ignore 2 GiB file size limitations).


A core limitation is the fact that command lines, environment variables and echoed out lines are all limited to 8 KiB, so dealing with files that contain longer lines is difficult. However, if one can life with that, here is an approach that uses a for /F to read the file, echo to output each line, including the terminating line-break, but, for the very last line, with an end-of-file character (ASCII 0x1A) inserted before the line-break; that file is then copied by copy, which is capable of truncating the end-of-character and everything behind, eventually resulting in a file without a final line-break (if the file has got empty lines at the end, leading to multiple consecutive line-breaks, only a single one becomes removed). All this is necessary to retain the original text and to avoid issues with special characters or sequences:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_FILE=%~dp0list.txt" & rem // (path to the file to remove the final line-break from)
set "_CHRF=%~dp0list.chr" & rem // (path to a file that receives a end-of-file character)
set "_TMPF=%~dp0list.tmp" & rem // (path to another temporary file)

rem // Skip processing file if it does not contain a final DOS/Windows-style line-break:
for %%I in ("%_FILE%") do (
    findstr /V "$" "%%~I" > nul && (echo Skipping file `%%~nxI`.& exit /B)
    < nul set /P ="Processing file `%%~nxI`... "
)
rem // Retrieve end-of-file character:
copy /Y /A nul "%_CHRF%" > nul
for /F "usebackq" %%I in ("%_CHRF%") do set "EOF=%%I"
rem // Write to temporary file:
> "%_TMPF%" (
    set "PREV="
    rem // Iterate through lines of the file (each of which must be shorter than 8 KiB):
    for /F "delims=" %%J in ('findstr /N "^" "%_FILE%"') do (
        rem // Output each line but delayed by one loop iteration:
        if defined PREV (
            setlocal EnableDelayedExpansion
            echo(!PREV:*:=!
            endlocal
        )
        set "PREV=%%J"
    )
    rem // Specifically handle last line by appending an end-of-line character:
    setlocal EnableDelayedExpansion
    echo(!PREV:*:=!!EOF!
    endlocal
)
rem // Copy temporary file over original one regarding the end-of-line character:
copy /Y "%_TMPF%" /A "%_FILE%" /B > nul
echo done.
rem // Clean up unneeded files:
del "%_CHRF%" "%_TMPF%"

endlocal
exit /B

A possible way to avoid the 8 KiB line length limitation is to utilise certutil.exe and its -encodehex verb to encode the file as a hexadecimal string, which is then read by set /P and which can easily be edited since there are no more special characters; the final line-break is removed by deleting the string 0d0a from the end of the hexadecimal string, whereupon it becomes decoded back to text using the -decodehex verb of certutil. Unfortunately, certutil introduces a file size limitation of a few tens of MiB:

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_FILE=%~dp0list.txt" & rem // (path to the file to remove the final line-break from)
set "_HEXF=%~dp0list.hex" & rem // (path to a file that receives the hexadecimal stream)
set "_TMPF=%~dp0list.tmp" & rem // (path to another temporary file)

rem // Skip processing file if it does not contain a final DOS/Windows-style line-break:
for %%I in ("%_FILE%") do (
    findstr /V "$" "%%~I" > nul && (echo Skipping file `%%~nxI`.& exit /B)
    < nul set /P ="Processing file `%%~nxI`... "
)
rem // Encode file into a hexadecimal stream (there is a size limit of few tens of MiB):
certutil -f -v -encodehex "%_FILE%" "%_HEXF%" 12 > nul
rem // Rounded up integer division; `+2` for final line-break of the hexadecimal stream:
for %%I in ("%_HEXF%") do set /A "LOOP=1+(%%~zI-1+2)/1023"
setlocal EnableDelayedExpansion
rem // Read from hexadecimal file, write into temporary file:
< "!_HEXF!" > "!_TMPF!" (
    set "PREV=" & set "CURR="
    rem // Iterate one more time as the above integer division of the file size gives:
    for /L %%J in (0,1,%LOOP%) do (
        rem // Try to read a hexadecimal fragment:
        set /P CURR="" && (
            rem // Reading successful, hence return fragment from last iteration:
            < nul set /P ="!PREV!"
            set "PREV=!CURR!"
        ) || (
            rem // Reading failed, so end of data is reached; remove final line-break:
            if "!PREV:~-4!"=="0d0a" (
                < nul set /P ="!PREV:~,-4!"
            ) else if "!PREV:~-2!"=="0a" (
                < nul set /P ="!PREV:~,-2!" & rem // (this handles Unix-style files)
            ) else (
                < nul set /P ="!PREV!" & rem // (this should normally never be reached)
            )
        )
    )
)
endlocal
rem // Decode temporary file with reduced hexadecimal stream, overwrite original file:
certutil -f -v -decodehex "%_TMPF%" "%_FILE%" 12 > nul
echo done.
rem // Clean up unneeded files:
del "%_HEXF%" "%_TMPF%"

endlocal
exit /B
于 2022-02-01T18:57:31.130 回答