如何避免脚本的多个实例,同时允许在不更改标题的情况下再次启动脚本

Bri*_*top 1 batch-file

我有这个脚本应该只在单个实例中运行。我确保这种情况不会发生的方法是

tasklist /fi "imagename eq cmd.exe" /v | find "lootbot" && echo already running && pause && exit /b
title lootbot
Run Code Online (Sandbox Code Playgroud)

然后正常退出,以便脚本可以重新启动......

:action8
cd /d "%~dp0"
title command prompt
echo type launch to return to lootbot
exit /b
Run Code Online (Sandbox Code Playgroud)

问题是,每当脚本因错误而崩溃时,如果不先手动将标题重新设置为其他内容,它就不允许我重新启动它。

当然,这不是一个大问题,但我正在构建这个供其他人使用,所以我在这里寻找一个易于使用的解决方案。我在想如果有一种方法可以确定当前命令提示符是否有标题lootbot,那么这个问题就可以自动避免。这是整个脚本以防万一。

@echo off
tasklist /fi "imagename eq cmd.exe" /v | find "lootbot" && echo lootbot already running, press a key to exit && pause && exit /b
title lootbot
:: enable save files location (persistant memory)
set "saves=%appdata%\lootbot"
if not exist "%saves%" mkdir "%saves%"
:: create/load saves, echo first
if exist "%saves%\echoes\launch" echo on
if not exist "%saves%\loopdelay" echo 300>"%saves%\loopdelay"
if not exist "%saves%\promptdelay" echo 60>"%saves%\promptdelay"
set /p loopdelay=<"%saves%\loopdelay" & set /p promptdelay=<"%saves%\promptdelay"
:: advanced prep
chcp 65001 >nul
set "path=%path%;%~dp0;c:\program files\filebot"
wmic process where name="cmd.exe" call setpriority "idle" >nul
:: additional scripts (all-in-one launcher)
start vpn.cmd

:: add "going legit" to vpn or somewhere (meaning close torrents and vpn, reactivate vpn if torrents appear, or close torrents)
:: add skippable delay here to auto-avoid possible mishandling ones being checked in qbittorrent
cls
:menu
@colorx -c 08
@if exist "%saves%\echoes\launch" echo on
@cd /d "%~dp0"
@set "msg=lootbot ready (%time:~0,2%:%time:~3,2%) wait %loopdelay%s or enter command"
@set "msg=%msg:( =(%" & rem this removes the blank space from early hours
@choice /t %loopdelay% /c rcplsjdq /n /d r /m "%msg% [R]un [C]lear [P]ause [L]ist [S]etup [J]obs [D]onate [Q]uit: "
:: add selective choices here, based on what scripts are available. might need those scripts to be names or placed different to autodetect
@goto action%errorlevel%
@goto menu

:action1
:routine
:: run now/default infinite loop
call report %~n0 import
call report %~n0 direct
:: idea: add small amount of random files to scan?
goto menu

:action2
:clear
cls
goto menu

:action3
pause
goto menu

:action4
:playlist
call report %~n0 player
goto menu

:action5
:settings
call report %~n0 option
goto menu

:action6
:caring
call report %~n0 caring
goto menu

:action7
:donate
call report %~n0 donate
goto menu

:action8
:exit
:: quit back to command prompt
cd /d "%~dp0"
title command prompt
echo use command launch to return to lootbot, bye!
exit /b
Run Code Online (Sandbox Code Playgroud)

dbe*_*ham 5

通过策略性地使用重定向和 CALL 来建立锁定文件,可以轻松完成此操作。只有一个实例可以对锁定文件进行写访问。第二个实例的尝试将会失败。第一个实例一旦退出就会释放锁,无论它如何终止。

我使用多个重定向阶段来隐藏不需要的错误消息,但主例程具有正常的 stdout 和 stderr。我添加%*将原始参数传递给 main. main 中唯一“奇怪”的情况是%0代替:main执行脚本。但%~f0可用于获取执行脚本的完整路径。

测试.bat

@echo off
9>&2 2>nul (call :lockAndRestoreStdErr %* 8>"%~f0.lock") && (
  del "%~f0.lock"
) || (
  echo Only one instance allowed - "%~f0" is already running >&2
)
exit /b

:lockAndRestoreStdErr
call :main %* 2>&9
exit /b 0

:main
echo        %%0 = %0
echo    "%%~f0" = "%~f0"
echo Arguments = %*
pause
exit /b
Run Code Online (Sandbox Code Playgroud)

实例 1 输出示例

C:\test>test arg1 arg2
       %0 = :main
   "%~f0" = "C:\test\test.bat"
Arguments = arg1 arg2
Press any key to continue . . .
Run Code Online (Sandbox Code Playgroud)

实例 1 仍在运行时实例 2 的输出示例

C:\test>test arg1 arg2
Only one instance allowed - "C:\test\test.bat" is already running

C:\test>
Run Code Online (Sandbox Code Playgroud)

一旦按下某个键,实例 1 将终止,然后实例 2 可以运行该脚本。

编辑

实际上你不需要单独的锁定文件。您可以使用批处理脚本本身作为锁定文件。请记住使用>>而不是>,否则您将擦除脚本!

@echo off
9>&2 2>nul (call :lockAndRestoreStdErr %* 8>>"%~f0") || (
  echo Only one instance allowed - "%~f0" is already running >&2
)
exit /b

:lockAndRestoreStdErr
call :main %* 2>&9
exit /b 0

:main
echo        %%0 = %0
echo    "%%~f0" = "%~f0"
echo Arguments = %*
pause
exit /b
Run Code Online (Sandbox Code Playgroud)

如果用户没有脚本的写入权限,则上述方法都不起作用。在这种情况下,您应该将锁定文件放入该%temp%文件夹中。

@echo off
9>&2 2>nul (call :lockAndRestoreStdErr %* 8>"%temp%\%~nx0.lock") && (
  del "%temp%\%~nx0.lock"
) || (
  echo Only one instance allowed - "%~f0" is already running >&2
)
exit /b

:lockAndRestoreStdErr
call :main %* 2>&9
exit /b 0

:main
echo        %%0 = %0
echo    "%%~f0" = "%~f0"
echo Arguments = %*
pause
exit /b
Run Code Online (Sandbox Code Playgroud)

编辑 - 回答评论中的问题

要将上述技术放入您的脚本中,只需删除您的任务列表行,并将其替换为我的技术,这样您的脚本的顶部如下所示:

@echo off
9>&2 2>nul (call :lockAndRestoreStdErr %* 8>>"%~f0") || (
  echo Only one instance allowed - "%~f0" is already running >&2
  pause
)
exit /b

:lockAndRestoreStdErr
call :main %* 2>&9
exit /b 0

:main
title lootbot
:: enable save files location (persistant memory)
etc...
Run Code Online (Sandbox Code Playgroud)