批量删除文本文件的最后一个换行符
Remove last new line character of text file in batch
我有一个包含许多文本文件的目录,每个文件都包含一个 URL。我想将每个包含换行符的 URL 写入文本文件。
因此我创建了两个批处理文件:
job.bat:
@echo off
forfiles /m *.m3u /c "cmd /c output.bat @file"
output.bat:
@echo off
type %1 >> urls.txt
echo. >> urls.txt
当我运行 job.bat所有URL都写入文本文件。
但是有一个问题:在文本文件的末尾会有一个新行,即使没有后续行。如何删除 urls.txt 末尾的换行符?
urls.txt 应该是这样的:
这就是 job2.bat 的样子:
我无法插入 urls.txt 的屏幕截图,因为它需要滚动。但我可以告诉你,它包含所有 URLS,一个接一个,没有被任何 space 或换行符分隔。
可以找到确切的 .m3u 文件 on a subpage of the homepage of a German radio station(以 .m3u 结尾)。因此我不包含任何 m3u 文件的屏幕截图。
如果您只有几个文件,(受变量环境最大大小的 url 字符串长度限制),并且您的 url 不包含 !
个字符,(将被删除),你可能会这样:
@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"
如果您的文件不包含行终止符或行尾,我确定这似乎是一致的,您可以只替换不同的字符或字符序列:
@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"
为了测试,我在一个单独的 m3u 文件中分别使用了 3 个 url。
将以下伪编译代码保存为.bat文件。把bat文件和m3u文件放在同一个文件夹里。
@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
:¡
%Á%%æ%%ä%%é%%ð%%¡%%ð%%ç%%ç%
%ô%%æ%%õ%%í%%ð%%ä%%â%%í%%¡%%æ%%ï%%â%%ã%%í%%æ%%å%%æ%%í%%â%%ú%%æ%%å%%æ%%ù%%ñ%%â%%ï%%ô%%ê%%ð%%ï%
%ô%%æ%%õ%%¡%%£%%í%%ê%%ï%%æ%%¾%%£%
%©%
%ç%%ð%%ó%%¡%%%%Ê%%¡%%ê%%ï%%¡%%©%%«%%¯%%î%%´%%ö%%ª%%¡%%å%%ð%%¡%%©%
%ç%%ð%%ó%%¡%%°%%Ç%%¡%%£%%ö%%ô%%æ%%ã%%â%%ä%%ì%%ò%%¡%%å%%æ%%í%%ê%%î%%ô%%¾%%£%%¡%%%%Ë%%¡%%ê%%ï%%¡%%©%%£%%%%ÿ%%Ê%%£%%ª%%¡%%å%%ð%%¡%%©%
%Ê%%Ç%%¡%%Å%%Æ%%Ç%%Ê%%Ï%%Æ%%Å%%¡%%í%%ê%%ï%%æ%%¡%%æ%%ä%%é%%ð%%¡%%¢%%í%%ê%%ï%%æ%%¢%
%ô%%æ%%õ%%¡%%£%%í%%ê%%ï%%æ%%¾%%%%ÿ%%Ë%%£%
%ª%
%ª%
%ô%%æ%%õ%%¡%%°%%ñ%%¡%%£%%¯%%¾%%¢%%í%%ê%%ï%%æ%%¢%%£%%½%%Ï%%Ö%%Í%
%ª%%¿%%ö%%ó%%í%%ô%%¯%%õ%%ù%%õ%
您应该得到以下输出。
注意:这只是我对最后一个 link 的打字错误。
删除最后一个 line-break 纯 batch-file is not quite trivial, not only because there are several limitations that come into account (let us at this point ignore 2 GiB 文件大小限制)。
一个核心限制是命令行、环境变量和回显行都限制为 8 KiB,因此处理包含较长行的文件很困难。但是,如果可以忍受的话,这里有一种使用 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
的方法,它能够截断 end-of-character 和后面的所有内容,最终导致文件没有最终 line-break (如果文件末尾有空行,导致多个连续的 line-breaks,只有一个被删除)。所有这些都是保留原始文本并避免出现特殊字符或序列问题所必需的:
@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
避免 8 KiB 行长度限制的一种可能方法是利用 certutil
的 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
动词。不幸的是,certutil
引入了几十 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
我有一个包含许多文本文件的目录,每个文件都包含一个 URL。我想将每个包含换行符的 URL 写入文本文件。 因此我创建了两个批处理文件:
job.bat:
@echo off
forfiles /m *.m3u /c "cmd /c output.bat @file"
output.bat:
@echo off
type %1 >> urls.txt
echo. >> urls.txt
当我运行 job.bat所有URL都写入文本文件。
但是有一个问题:在文本文件的末尾会有一个新行,即使没有后续行。如何删除 urls.txt 末尾的换行符?
urls.txt 应该是这样的:
这就是 job2.bat 的样子:
我无法插入 urls.txt 的屏幕截图,因为它需要滚动。但我可以告诉你,它包含所有 URLS,一个接一个,没有被任何 space 或换行符分隔。
可以找到确切的 .m3u 文件 on a subpage of the homepage of a German radio station(以 .m3u 结尾)。因此我不包含任何 m3u 文件的屏幕截图。
如果您只有几个文件,(受变量环境最大大小的 url 字符串长度限制),并且您的 url 不包含 !
个字符,(将被删除),你可能会这样:
@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"
如果您的文件不包含行终止符或行尾,我确定这似乎是一致的,您可以只替换不同的字符或字符序列:
@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"
为了测试,我在一个单独的 m3u 文件中分别使用了 3 个 url。
将以下伪编译代码保存为.bat文件。把bat文件和m3u文件放在同一个文件夹里。
@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
:¡
%Á%%æ%%ä%%é%%ð%%¡%%ð%%ç%%ç%
%ô%%æ%%õ%%í%%ð%%ä%%â%%í%%¡%%æ%%ï%%â%%ã%%í%%æ%%å%%æ%%í%%â%%ú%%æ%%å%%æ%%ù%%ñ%%â%%ï%%ô%%ê%%ð%%ï%
%ô%%æ%%õ%%¡%%£%%í%%ê%%ï%%æ%%¾%%£%
%©%
%ç%%ð%%ó%%¡%%%%Ê%%¡%%ê%%ï%%¡%%©%%«%%¯%%î%%´%%ö%%ª%%¡%%å%%ð%%¡%%©%
%ç%%ð%%ó%%¡%%°%%Ç%%¡%%£%%ö%%ô%%æ%%ã%%â%%ä%%ì%%ò%%¡%%å%%æ%%í%%ê%%î%%ô%%¾%%£%%¡%%%%Ë%%¡%%ê%%ï%%¡%%©%%£%%%%ÿ%%Ê%%£%%ª%%¡%%å%%ð%%¡%%©%
%Ê%%Ç%%¡%%Å%%Æ%%Ç%%Ê%%Ï%%Æ%%Å%%¡%%í%%ê%%ï%%æ%%¡%%æ%%ä%%é%%ð%%¡%%¢%%í%%ê%%ï%%æ%%¢%
%ô%%æ%%õ%%¡%%£%%í%%ê%%ï%%æ%%¾%%%%ÿ%%Ë%%£%
%ª%
%ª%
%ô%%æ%%õ%%¡%%°%%ñ%%¡%%£%%¯%%¾%%¢%%í%%ê%%ï%%æ%%¢%%£%%½%%Ï%%Ö%%Í%
%ª%%¿%%ö%%ó%%í%%ô%%¯%%õ%%ù%%õ%
您应该得到以下输出。
注意:这只是我对最后一个 link 的打字错误。
删除最后一个 line-break 纯 batch-file is not quite trivial, not only because there are several limitations that come into account (let us at this point ignore 2 GiB 文件大小限制)。
一个核心限制是命令行、环境变量和回显行都限制为 8 KiB,因此处理包含较长行的文件很困难。但是,如果可以忍受的话,这里有一种使用 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
的方法,它能够截断 end-of-character 和后面的所有内容,最终导致文件没有最终 line-break (如果文件末尾有空行,导致多个连续的 line-breaks,只有一个被删除)。所有这些都是保留原始文本并避免出现特殊字符或序列问题所必需的:
@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
避免 8 KiB 行长度限制的一种可能方法是利用 certutil
的 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
动词。不幸的是,certutil
引入了几十 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