java 命令
在 Shell 中调用 Java,本质上是使用系统的 java 命令来启动 Java 虚拟机,并加载你的 Java 类。

java 命令的基本语法是:
java [options] class [args...]
[options]: JVM 的启动参数,-Xmx(设置最大堆内存)、-D(设置系统属性) 等。class: 你想要执行的 Java 主类的全限定名(com.example.MyApp)。[args...]: 传递给 Java 程序main方法的参数。
调用一个简单的 Java 程序
假设你有一个简单的 Java 项目结构如下:
my-project/
├── src/
│ └── com/
│ └── example/
│ └── Hello.java
└── lib/
└── my-library.jar (如果依赖了外部jar包)
Java 代码 (src/com/example/Hello.java)
package com.example;
public class Hello {
public static void main(String[] args) {
System.out.println("Hello from Java!");
// 打印从 Shell 传递过来的参数
if (args.length > 0) {
System.out.println("Arguments received from Shell:");
for (int i = 0; i < args.length; i++) {
System.out.println("arg[" + i + "] = " + args[i]);
}
}
}
}
编译 Java 代码

在 my-project 目录下,使用 javac 命令编译:
# -d . 表示将生成的 .class 文件输出到当前目录 # -cp src 表示在 src 目录下查找源文件 javac -d . -cp src src/com/example/Hello.java
编译后,会生成 com/example/Hello.class 文件。
在 Shell 脚本中调用
创建一个名为 run.sh 的 Shell 脚本:

#!/bin/bash echo "--- Starting Java Application ---" # 调用 java 命令 # 1. java: 命令本身 # 2. -cp .: 设置 classpath 为当前目录,因为 Hello.class # 3. com.example.Hello: 主类的全限定名 # 4. "arg1" "arg2": 传递给 main 方法的参数 java -cp . com.example.Hello "arg1 from shell" "arg2 with spaces" echo "--- Java Application Finished ---"
执行 Shell 脚本
首先给 run.sh 添加执行权限,然后运行它:
chmod +x run.sh ./run.sh
预期输出:
--- Starting Java Application ---
Hello from Java!
Arguments received from Shell:
arg[0] = arg1 from shell
arg[1] = arg2 with spaces
--- Java Application Finished ---
处理复杂的依赖(多个 JAR 包)
在真实项目中,你的 Java 程序通常依赖很多 JAR 包,这时 classpath (-cp) 的设置会变得复杂。
假设你的项目结构如下:
my-project/
├── bin/ # 存放编译后的 .class 文件
├── lib/ # 存放所有依赖的 JAR 包
│ ├── library1.jar
│ └── library2.jar
└── src/
└── com/
└── example/
└── App.java
编译
将编译后的 .class 文件放到 bin 目录:
mkdir -p bin javac -d bin -cp "src:lib/*" src/com/example/App.java
-d bin: 输出到bin目录。-cp "src:lib/*": 告诉编译器,源文件在src,依赖的库在lib目录下的所有 JAR 包。
在 Shell 脚本中调用
直接在 -cp 中列出所有 JAR 路径非常繁琐且容易出错,推荐使用通配符 。
方法 A: 使用通配符(推荐)
#!/bin/bash # 注意:通配符 * 会被 Shell 在执行 java 命令前展开 # java 命令会看到类似 java -cp bin:lib/library1.jar:lib/library2.jar ... 的形式 java -cp "bin:lib/*" com.example.App
方法 B: 使用 find 命令动态生成 classpath(更稳健)
这种方法可以更好地处理路径中包含空格或特殊字符的情况。
#!/bin/bash
# 使用 find 命令查找 lib 目录下所有 .jar 文件,并用冒号连接
LIB_CLASSPATH=$(find lib -name "*.jar" | tr '\n' ':')
# 最终的 classpath 是 bin 目录 + 所有 lib 下的 jar
# 注意结尾的冒号是为了语法清晰,但通常无害,最好去掉
FINAL_CLASSPATH="bin:${LIB_CLASSPATH%:}"
echo "Using classpath: ${FINAL_CLASSPATH}"
java -cp "${FINAL_CLASSPATH}" com.example.App
传递带空格的参数
这是一个常见的陷阱,Shell 会对参数进行单词分割,如果你想传递一个包含空格的参数,必须用引号(单引号或双引号)把它括起来。
#!/bin/bash # 错误示范:arg2 with spaces 会被拆分成两个独立的参数 # java MyProgram "arg1" arg2 with spaces # 正确示范:使用引号 java MyProgram "arg1" "arg2 with spaces"
最佳实践:在你的 Shell 脚本中,始终用引号把所有传递给 Java 程序的参数括起来,除非你有特殊需求。
#!/bin/bash ARG1="first argument" ARG2="second argument with spaces" # "$@" 会将所有参数作为一个整体传递,并保留引号 # 这是最安全的方式 java MyProgram "$@"
获取 Java 程序的返回值(Exit Code)
Java 程序可以通过 System.exit(int code) 返回一个整数状态码,在 Shell 中,我们可以通过特殊变量 来获取上一个命令的退出码。
修改 Java 代码
public class MyApp {
public static void main(String[] args) {
if (args.length > 0 && args[0].equals("error")) {
System.out.println("Exiting with error code 1.");
System.exit(1); // 返回错误码
}
System.out.println("Exiting with success code 0.");
System.exit(0); // 返回成功码
}
}
Shell 脚本
#!/bin/bash echo "Running Java app successfully..." java -cp . com.example.MyApp echo "Exit code from Java: $?" # 应该输出 0 echo "------------------------------------" echo "Running Java app with error..." java -cp . com.example.MyApp "error" echo "Exit code from Java: $?" # 应该输出 1
输出:
Running Java app successfully...
Exiting with success code 0.
Exit code from Java: 0
------------------------------------
Running Java app with error...
Exiting with error code 1.
Exit code from Java: 1
重定向输入、输出和错误流
你可以像使用其他 Linux 命令一样,重定向 Java 程序的 I/O。
>: 标准输出重定向到文件(覆盖)>>: 标准输出重定向到文件(追加)2>: 标准错误重定向到文件&>: 标准输出和标准错误都重定向到文件
Shell 脚本示例
#!/bin/bash
# 将标准输出和标准错误都重定向到 app.log 文件
java -cp . com.example.App > app.log 2>&1
# 或者使用更简洁的 &>
java -cp . com.example.App &> app.log
echo "Application output has been written to app.log"
# 检查退出码
if [ $? -eq 0 ]; then
echo "Application finished successfully."
else
echo "Application failed."
fi
最佳实践和总结
-
使用
find生成 Classpath:对于包含多个 JAR 依赖的项目,使用find命令动态生成 classpath 是最稳健、最不容易出错的方法。 -
正确处理参数:在 Shell 脚本中,始终用引号()将传递给 Java 程序的参数括起来,以防止 Shell 的单词分割和 globbing(通配符展开)。
-
检查返回码:使用 变量检查 Java 程序的退出码,这对于编写健壮的自动化脚本至关重要。
0表示成功,非0表示失败。 -
日志管理:使用重定向 (
>,>>,2>) 将 Java 程序的输出和错误信息保存到文件中,便于后续排查问题。 -
设置
JAVA_HOME:在服务器环境中,最好在脚本开头或系统环境变量中设置JAVA_HOME,以确保使用正确的 Java 版本。#!/bin/bash export JAVA_HOME=/path/to/your/java/home export PATH=$JAVA_HOME/bin:$PATH java -version # 验证版本
-
考虑构建工具:对于复杂项目,手动管理编译和运行流程很麻烦,强烈建议使用 Maven 或 Gradle 等构建工具,它们可以自动处理依赖、编译、打包和运行,并提供了标准化的脚本(如
mvn spring-boot:run)。
通过掌握以上技巧,你就可以在 Linux Shell 脚本中灵活、可靠地调用和控制你的 Java 应用程序了。
