从 java 运行 shell 脚本 - 未完成任务
我有一个java程序,它应该启动一个shell脚本。该脚本包含 6 个按顺序执行的任务。 java程序启动脚本并启动(正如我看到的日志)。但 10-15 秒后,执行停止,甚至在 shell 脚本中的第一个任务完成之前。奇怪的是,当我在终端中启动脚本时,脚本运行良好。为了避免在执行脚本时程序挂起的风险,我在单独的线程中启动它。可能的原因是什么?
Java 代码 -
try {
log.info("run cmd - "+optionsRun);
String[] cmdLine = (String[]) optionsRun.toArray(new String[optionsRun.size()]);
Process process = Runtime.getRuntime().exec(cmdLine);
log.info("end run cmd " + this.getScriptPath());
//
// BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
// writer.write("mypwd");
// writer.flush();
// writer.close();
InputStream is = process.getErrorStream();
String error = inputStreamToStringValue(is);
log.trace("Eventual error was : " + error);
InputStream os = process.getInputStream();
String output = inputStreamToStringValue(os);
log.info("Eventual output was : " + output);
if (error!=null & error.length()>0) {
throw new ActionProcessingException("An error occurred when running the script :'"+this.getScriptPath()+"' with following error message : "+error);
}else {
log.info("Script run ended successfully.");
}
shell 脚本看起来是这样的 -
#!/bin/sh
# ./publish <path-to-publish-home-folder> <workspace_id> <start_date> <end_date>
# ./publish <path-to-publish-home-folder> 100011 2010-01-06-12:00:00-CET 2012-01-14-19:00:00-CET
rm -f $1/publish.log
echo 'Start publish' >> $1/publish.log
echo $0 $1 $2 $3 $4 $5 $6 $7 $8 $9 >> $1/publish.log
# lancement de l'export RDF du domaine
cd $1/1-export-domain
echo "Starting export domain with the command - ./export.sh $2" >> $1/publish.log
./export.sh $2
# lancement de l'export des translations du domaine
cd $1/2-export-trans
echo "Starting export domain(translated) with the command - ./export.sh $2" >> $1/publish.log
./export.sh $2
.....
.....
a couple of more steps like 1 and 2
....
提前致谢,
I have a java program which is supposed to launch a shell script. The script contains 6 tasks which are to be executed in sequence. The java program launches the script and it starts(as I see the logs). But after 10-15 seconds, the execution stops, even before the first task in the shell script is completed. The strange thing is that the script runs fine when I launch it in terminal. To avoid risking the program to hang while the script is being executed, I launch it in a separate thread. What might be a probable reason?
Java code -
try {
log.info("run cmd - "+optionsRun);
String[] cmdLine = (String[]) optionsRun.toArray(new String[optionsRun.size()]);
Process process = Runtime.getRuntime().exec(cmdLine);
log.info("end run cmd " + this.getScriptPath());
//
// BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(process.getOutputStream()));
// writer.write("mypwd");
// writer.flush();
// writer.close();
InputStream is = process.getErrorStream();
String error = inputStreamToStringValue(is);
log.trace("Eventual error was : " + error);
InputStream os = process.getInputStream();
String output = inputStreamToStringValue(os);
log.info("Eventual output was : " + output);
if (error!=null & error.length()>0) {
throw new ActionProcessingException("An error occurred when running the script :'"+this.getScriptPath()+"' with following error message : "+error);
}else {
log.info("Script run ended successfully.");
}
And the shell script looks this way -
#!/bin/sh
# ./publish <path-to-publish-home-folder> <workspace_id> <start_date> <end_date>
# ./publish <path-to-publish-home-folder> 100011 2010-01-06-12:00:00-CET 2012-01-14-19:00:00-CET
rm -f $1/publish.log
echo 'Start publish' >> $1/publish.log
echo $0 $1 $2 $3 $4 $5 $6 $7 $8 $9 >> $1/publish.log
# lancement de l'export RDF du domaine
cd $1/1-export-domain
echo "Starting export domain with the command - ./export.sh $2" >> $1/publish.log
./export.sh $2
# lancement de l'export des translations du domaine
cd $1/2-export-trans
echo "Starting export domain(translated) with the command - ./export.sh $2" >> $1/publish.log
./export.sh $2
.....
.....
a couple of more steps like 1 and 2
....
Thanks in advance,
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我不确定,但我会推荐两个链接来帮助您弄清楚。
第一个是关于 Runtime.exec() 的非常古老的:
http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html
第二个是关于
ProcessBuilder
,旨在替换Runtime.exec()
的新类:http://www.java-tips.org/java-se-tips/java.util/from-runtime.exec -to-processbuilder.html
I'm not sure, but I'll recommend two links that might help you figure it out.
The first is a very old one about
Runtime.exec()
:http://www.javaworld.com/javaworld/jw-12-2000/jw-1229-traps.html
The second is about
ProcessBuilder
, the new class intended to replaceRuntime.exec()
:http://www.java-tips.org/java-se-tips/java.util/from-runtime.exec-to-processbuilder.html
我不能确定我的猜测是问题出在您的方法
inputStreamToStringValue(is)
中。它读取 STDERR 并且在读取时阻塞。当它没有从 STDERR 读取任何内容但进程尚未终止时,您将被永远阻止。我建议您使用 ProcessBuilder:
现在您可以一起读取 STDIN 和 STDERR。
如果您仍然想单独阅读它们,您有两种解决方案。
首先按照您现在所做的操作,但不要在读取时阻塞,即在每次调用 read 之前调用
in.available()
,然后仅读取之前可用的字节数。第二种方法是使用 shell 重定向。运行脚本并将其 STDOUT 和 STDERR 重定向到临时文件。然后等待进程终止,然后从文件中读取。我个人认为这个解决方案更简单、更稳健。
祝你好运。
I cannot be sure I my guess is that the problem is in your method
inputStreamToStringValue(is)
. It reads STDERR and it is blocking on read. When it has nothing to read from STDERR but the process is not terminated yet you will be blocked forever.I'd recommend you to use ProcessBuilder:
Now you can read STDIN and STDERR together.
If you still want to read them separately you have 2 solutions.
First do as you are doing now but do not be block on read, i.e. call
in.available()
before each call of read and then read only number of bytes that were previously available.Second way is to use the shell redirection. Run you script and redirect its STDOUT and STDERR to temporary files. Then wait until your process terminates and then read from files. I personally think that this solution is easier and more robust.
Good luck.