curl 批处理脚本,处理带有CR行尾的字符串

bweufnob  于 2022-11-13  发布在  其他
关注(0)|答案(2)|浏览(211)
  • 我决定重新格式化我的问题,由于用户的意见(感谢所有)和新的知识,我已经得到了。我不会打开一个新的职位,因为主要问题仍然是相同的:*

如果某个程序(如CURL)生成的字符串没有LF终止符,如何逐行动态处理这些字符串?

CURL产生每一行的时间间隔大约为1秒。我只需要从CURL输出中选择一些字段进行进一步处理(当前速度、下载的字节数、下载的百分比),所以我需要处理每一个新出现的行。但我不能,因为每一行都以CR结尾。
在下载完成之前,FOR循环不会在CMD窗口中显示任何内容,其他用户向我解释了原因:

FOR /F "delims=" %%x in ('curl ... http://some_url 2^>^&1') do echo %%x

于是,我被迫放弃了FOR

curl ... http://some_url | string_handler.bat

使用JREPL动态地将CR替换为CRLF

curl ... http://some_url  2>&1 | jrepl "\r([^\n])" "\r\n$1" /xseq

但是,这种解决方案在CURL完成后会产生空洞输出,而不是逐行输出,因为如果字符串没有LF终止符,则PIPE就没有任何内容(感谢@Stephan)。也许有解决方案可以绕过PIPE行为?
为了解决这个问题,我做了一个简单的脚本-模拟CURL输出。这是倒计时计时器,它每1秒产生一行与CR终止符,除了第一行和最后一行有CRLF

:: bears.bat

@echo off
setlocal enabledelayedexpansion

::Define LF variable containing a linefeed (0x0A)
(set LF=^
%=empty line%
)

::Get a CR character (0x0D)
for /F %%a in ('copy /Z "%~F0" NUL') do set "CR=%%a"

:: First argument is CountDown high level, default 4 sec
if "%1"=="" (set /a high=4) else (set /a high=%1)

echo Hello bears
for /l %%i in (%high%,-1,0) do (
    if %%i gtr 0 (
        <nul set /p="Counter: %%i!CR!" 
    ) else (
        <nul set /p="Counter: %%i!CR!!LF!"
    )
    :: Pause 1 sec
    if %%i gtr 0 ping 127.0.0.1 -n 2 >nul
)
exit /b
sshcrbum

sshcrbum1#

如果你想把Mac的'CR'结尾行替换成Windows的'CRLF',我想这也是你所要求的,那么下面的方法应该可以实现:

@(For /F Delims^=^ EOL^= %%G In ('%SystemRoot%\System32\curl.exe
 "http://some_url" 2^>^&1') Do @(Set "LineWithCR=%%G"
 SetLocal EnabledelayedExpansion & Echo !LineWithCR!& EndLocal)) 1>"curl.log"

快速说明:
For /F命令在第一次出现“LF”时终止一行,如果前面是“CR ",则会删除该”CR“,但保留任何其他”CR“字符。如果展开包含”CR“的For变量(在本例中为%%G),则也会保留该”CR“。但是,如果展开环境变量%LineWithCR%,所有的“CR”字符都将被删除。但是,为了扩展包含“CR”的环境变量,您需要使用延迟扩展,例如!LineWithCR!

0mkxixxg

0mkxixxg2#

正如已经说过的,它不能用FOR /F循环来解决,因为它总是在开始循环之前等待完整的输出。
但它可以通过异步模式和两个线程来解决。
你可以测试一下,把call slowOutput.bat替换成call bears.bat

**重要提示:**使用者只需将所有可用内容读入line变量。

如果生产者足够快,这可能导致获取两个 * 行 *(带CR)。
以bears.bat为例:
Content of line = Counter: 4<CR>Counter: 3<CR>如果您的真实的curl命令产生了这个问题,您需要在<CR>字符处拆分line

@echo off
REM *** Trampoline jump for function calls of the form ex. "C:\:function:\..\MyBatchFile.bat"
FOR /F "tokens=3 delims=:" %%L in ("%~0") DO goto :%%L

REM Create an empty file, this has to exist before the consumer starts
break > async.tmp

REM Start the "producer" thread
start "" /b "cmd /c "%~d0\:producer:\..\%~pnx0"

REM The consumer thread runs parallel to the producer thread
call :consumer
exit /b

:producer
(
  call slowOutput.bat 
  (echo ende)
) > async.tmp
exit /b

:consumer
echo This is the consumer thread
setlocal EnableDelayedExpansion
< async.tmp call :_consumer
exit /b

:_consumer
set "line="
set /p line=

if not defined line goto :_consumer
if "!line!" EQU "ende" exit /b

echo(!line!
goto :_consumer

相关问题