首页 > 解决方案 > 有没有办法杀死一个持续超过 1 分钟的循环通道并批量进入下一个循环通道?

问题描述

jhove 脚本将在 for 循环中处理我的 %input% 目录中的所有文件 %%a。据我所知,taskkill 仅用于杀死 .exe 文件,而不是一次循环传递。此代码是否有可能等待 60 秒然后终止循环并转到下一个?就这样吧。像那样 timeout /t 1/nobreak>nul taskkill /F /IM "%%a"

 for /f "tokens=*" %%a in ('dir /b /a-d /s %input%\*.*') do ( 
         echo Verarbeite %%~na
         CALL jhove -m PDF-hul -h xml -o "%output%\%%~na_!count!.xml" "%%a"
         set /a count=count+1
         set /a loop3+=1
     )

标签: batch-filefor-looptaskkill

解决方案


你当然可以这样做:

> nul timeout /T 60 /NOBREAK
taskkill ...

但这将等待 60 秒,即使该过程在该时间过去之前退出。

我会改用轮询循环并通过tasklist进程是否仍在运行进行查询,如果没有,则继续处理下一项。这是实现该目标的一种可能方法(请参阅评论):

@echo off
setlocal EnableExtensions DisableDelayedExpansion

rem // Define constants here:
set "_INPUT=."               & rem // (path to input directory)
set "_OUTPUT=."              & rem // (path to output directory)
set "_MASK=*.*"              & rem // (input file name pattern)
set "_SCRIPT=%~dp0jhove.bat" & rem // (script to process input files by)
set "_TITLE=JHOVE"           & rem // (base window title of script process)
set "_FROZEN="               & rem // (only terminate frozen processes if not empty)
set /A "_TIMEOUT=60"         & rem // (timeout value for process; zero means none)

set /A "COUNT=0"
rem // Resolve output directory:
for %%D in ("%_OUTPUT%") do (
    rem // Iterate through all input files:
    for /F "delims=" %%F in ('dir /S /B /A:-D "%_INPUT%\%_MASK%"') do (
        rem // Process input files in a sub-routine:
        call :RUN -m PDF-hul -h xml -o "%%~fD\%%~nF_%%COUNT%%.xml" "%%~F"
        set /A "COUNT+=1"
    )
)

endlocal
exit /B


:RUN
    rem // Build unique window title:
    set "WTITLE=%_TITLE%_%RANDOM%"
    rem // Build image name from command prompt specification:
    for %%I in ("%ComSpec%") do set "IMAGE=%%~nxI"
    rem // Run script using unique window title:
    start "%WTITLE%" /D "%_INPUT%" "%ComSpec%" /D /S /C ^""%_SCRIPT%" %*^"
    rem // Skip polling loop in case timeout is set to zero, thus deactivated:
    if %_TIMEOUT% leq 0 goto :END
    rem // Set filter according to given configuration:
    if defined _FROZEN (set "FILTER=/FI "STATUS ne RUNNING"") else set "FILTER="
    rem // Try termination without forcing first:
    set "FORCE="
    rem // Reset timer:
    set /A "TIMER=0"
    rem // Reset error flag:
    set "ERR=0"
    :LOOP
    rem // Retrieve PID of running command prompt process with unique window title:
    set "PID=0"
    for /F "tokens=1* delims=:" %%T in ('
        2^> nul tasklist /FI "IMAGENAME eq %IMAGE%" /FI "WINDOWTITLE eq %WTITLE%" ^
            /FO LIST /V
    ') do (
        if "%%T"=="PID" for /F %%V in ("%%U") do set "PID=%%V"
        if "%%T"=="Status" for /F "tokens=*" %%V in ("%%U") do set "STATUS=%%V"
    )
    rem // Skip loop if no PID has been found (process might already be finished):
    if %PID% equ 0 goto :END
    rem // Wait for a second, so this is the polling rate:
    > nul timeout /T 1 /NOBREAK
    rem // Increment timer:
    set /A "TIMER+=1"
    rem // Check whether timeout limit is reached, loop if not:
    if %TIMER% leq %_TIMEOUT% goto :LOOP
    rem /* Loop if process is frozen, if desired (this filter (`/FI`) cannot applied
    rem    to `taskkill` below, because mismatch would not set the exit code, hence
    rem    use of conditional operators `&&` and `||` would not work): */
    if defined FILTER for /F "tokens=1* delims=:" %%T in ('
        2^> nul tasklist /FI "IMAGENAME eq %IMAGE%" /FI "WINDOWTITLE eq %WTITLE%" ^
            %FILTER% /FO LIST /V
    ') do if "%%T"=="INFO" goto :LOOP
    rem /* Try to terminate process with found PID (`taskkill` sets the exit code in
    rem    case filters `/PID` or `/IM` deliver a mismatch, but not for `/FI`): */
    > nul 2> nul taskkill /PID %PID% %FORCE% && (
        rem // Termination succeeded, so return information message:
        echo Successfully terminated process:
        call :MSG %*
        rem // Set error flag:
        set "ERR=1"
    ) || (
        rem // Termination failed:
        if not defined FORCE (
            rem // Normal termination failed, so try termination forcefully now:
            set "FORCE=/F"
            goto :LOOP
        ) else (
            rem // Forceful termination failed, so return error message:
            >&2 (
                echo Failed to terminate process:
                call :MSG %*
            )
            rem // Set error flag:
            set "ERR=2"
        )
    )
    :END
    rem /* Exit with exit code (`ErrorLevel`) set to `0` if no process had to be
    rem    terminated, `1` if at least one process had to be terminated, and `2`
    rem    if at least one process could not be terminated (forcefully): */
    exit /B %ERR%


:MSG
    rem // Return some process details:
    echo   PID         = %PID%
    echo   image name  = %IMAGE%
    echo   status      = %STATUS%
    echo   window title= %WTITLE%
    echo   command line= "%_SCRIPT%" %*
    echo/
    exit /B

推荐阅读