首页 > 解决方案 > 如何在后台运行java进程并退出脚本

问题描述

我正在尝试将 bash 脚本转换为批处理,但我遇到了这个问题。该脚本在后台运行一个 java 服务器,等待 5 秒,然后使用 exitcode 退出。但是批量,我无法...

运行服务器.sh

java -jar java_server.jar &
pid=$!
sleep 5
kill -0 $pid
cmdStatus=$?
if [ $cmdStatus -ne 0 ]
then
exit 1
fi
exit 0

运行服务器.bat

@echo off
set EXITCODE=0 
start /b java -jar java_server.jar
timeout /t 5
for /f "tokens=1 delims= " %%i in ('jps -m ^| findstr java_server') do set PID=%%i
IF "%PID" == "" (
set EXITCODE=1
)
EXIT EXITCODE

但是如果我运行上面的批处理脚本,我将永远无法否认 java 进程并且它永远不存在

标签: windowsshellbatch-filecommand-prompt

解决方案


批处理文件代码中的第一个错误是缺少将双引号括起来的环境变量的值与字符串%进行IF "%PID" == ""真正的比较。所以正确的是。有关字符串比较的更多详细信息,请参阅Windows 批处理文件中与 NEQ、LSS、GTR 等等效的符号PID""IF "%PID%" == ""

第二个错误是没有在环境变量周围的%最后一个命令行上使用两次来引用它的值,这将是正确的写为.EXIT EXITCODEEXITCODEEXIT %EXITCODE%

但是批处理文件最好写成如下:

@echo off
cd /D "%~dp0"
start "" /B javaw.exe -jar "%~dp0java_server.jar"
%SystemRoot%\System32\timeout.exe /T 5 /NOBREAK >nul
jps -m 2>nul | %SystemRoot%\System32\findstr.exe /L "java_server" >nul

批处理文件首先将批处理文件的目录设为当前目录,因为java_server.jar很可能在批处理文件的目录中。%~dp0扩展为驱动器和参数 0 的路径,即批处理文件。引用的文件路径%~dp0始终以反斜杠结尾,这是 Windows 上的目录分隔符,在将此字符串与文件或文件夹名称连接时应考虑到这一点。仅当批处理文件存储在使用UNC 路径访问的网络资源上时,命令CD才会失败因为 Windows 在默认情况下阻止使用 UNC 路径而不是驱动器号引用的目录成为当前目录,因为许多控制台应用程序工作不正确,当前目录不在具有驱动器号的驱动器上。

命令START将第一个双引号字符串解释为在单独的命令进程中运行 Windows 控制台应用程序时打开的控制台窗口的标题。/B在这种情况下,尽管java.exe是一个 Windows 控制台应用程序,但由于使用选项,没有打开控制台窗口。因此,""建议在启动 Windows GUI 应用程序时明确指定一个空字符串作为窗口标题,以避免将任何其他双引号参数字符串解释为可选窗口标题。

该选项/B被解释为背景。大多数人认为启动的应用程序与当前的命令进程分离。这适用于 Windows GUI 应用程序,但不适用于控制台应用程序(如java.exe. 当前命令进程的句柄STDIN与已启动的控制台应用程序的STDIN绑定。此外,已启动应用程序的句柄STDOUTSTDERR的输出被重定向到正在运行的命令进程的控制台窗口,该进程仍然会立即继续执行批处理脚本。选项/B意味着只运行与当前命令进程并行的控制台应用程序,而不打开新的控制台窗口,而不是在运行应用程序时完全脱离正在运行的命令进程。

在这种情况下,解决方案非常简单,因为javaw.exeWindows 版本的Java设计用于完全在后台运行 Java 应用程序,与启动它的进程分离。

一般用途的批处理文件最适合指定具有完整限定文件名的所有文件,这意味着具有完整路径、文件名和文件扩展名。Java可执行文件可以安装在任何地方,因此无法在批处理文件中指定此可执行文件的文件夹路径。Windows 命令处理器必须在当前目录或本地环境变量javaw文件夹列表中的任何文件夹中找到可执行文件。但至少可以指定带有文件扩展名的可执行文件,因为这个文件扩展名是众所周知的。PATHjavaw.exe

java_server.jar假设此文件与批处理文件存储在同一目录中,则使用完整路径指定JAR文件。批处理文件目录应该已经是当前目录,因此%~dp0根本不需要,但为了安全起见,使用完整路径指定文件并不重要。

接下来,标准 Windows 控制台应用程序TIMEOUT使用完整的限定文件名调用,并带有等待 5 秒牢不可破的选项(需要 Windows 7 或更高版本)并将其输出重定向到设备NUL

我对该文件一无所知,jps甚至没有安装Java。出于这个原因,我假设jps它是一个可执行文件或脚本,其文件扩展名列在本地环境变量PATHEXT中,并存储在批处理文件的目录或本地环境变量中列出的路径的任何其他目录中PATH。当然最好用文件扩展名指定这个文件,如果可能的话也用完整路径。

的标准输出jps重定向到 Windows 标准控制台应用程序FINDSTR的标准输入,并将错误输出重定向到设备NUL以抑制它。

FINDSTRjava_serverjps. _ FINDSTR的输出不感兴趣,因此也重定向到设备NUL以抑制它。

FINDSTR退出,0搜索到的字符串确实找到,而1没有找到。批处理文件应退出,并1在未成功启动 Java 服务器和0在 Java 服务器运行时退出。这与FINDSTR的退出代码完全匹配,因此无需执行任何其他操作。

cmd.exe在批处理文件执行期间,始终使用应用程序或命令设置的最后退出代码退出批处理文件的执行。这可以通过注释掉第二个命令行rem并保存它来验证,从命令提示符窗口中运行此批处理文件并在命令提示符窗口中运行下一个,if errorlevel 1 echo Java server not running!从而产生预期的输出Java server not running!。然后rem需要从批处理文件的第二个命令行中删除,然后再保存从命令提示符窗口中再次运行的批处理文件。第二个批处理文件执行完成后,再次运行会if errorlevel 1 echo Java server not running!导致没有输出,而运行会按预期if errorlevel 0 echo Java server is running.产生输出。Java server is running.

要了解使用的命令及其工作原理,请打开命令提示符窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。

  • call /?... 解释%~dp0
  • cd /?
  • echo /?
  • findstr /?
  • if /?
  • start /?

也可以看看:


推荐阅读