我有一个在 shell 中运行进程的 tomcat webapp,因为有几个实用程序在 java 中不可用。 此代码在其他机器上完美运行,但在我的公共(public)服务器上出现神秘问题。
String[] textAnalysisPipeline = {
"/bin/sh",
"-c",
"/bin/cat " + inputfileLoc +
" | tee /tmp/debug1 | " + loadJar + " " + jarOptLookupLoc + " " + optHfstLoc +
" 2>/dev/null | " + "tail -n+5" + // get rid of the header that hfst-ol.jar produces
" | tee /tmp/debug2 | cut -f 1-2" + // get rid of the "0.0" weights
" | tee /tmp/debug3 | " + cgConvLoc +
" | tee /tmp/debug4 | " + vislcg3Loc + " -g " + vislcg3DisGrammarLoc + // disambiguate with the constraint grammar
" | tee /tmp/debug5 > " + outputfileLoc};
log.debug("Text analysis pipeline: "+textAnalysisPipeline[2]);
Process process = Runtime.getRuntime().exec(textAnalysisPipeline);
process.waitFor();
我将字符串打印到日志中,它看起来像这样:(path/to/
不是实际路径)
/bin/cat /path/to/inputFile | tee /tmp/debug1 | java -jar /path/to/hfst-ol.jar /path/to/analyser.ohfst 2>/dev/null | tail -n+5 | tee /tmp/debug2 | cut -f 1-2 | tee /tmp/debug3 | /usr/local/bin/cg-conv | tee /tmp/debug4 | /path/to/vislcg3 -g /path/to/grammar.rlx | tee /tmp/debug5 > /path/to/outputFile
如果我从日志中复制此管道并从 bash 命令行运行它,我将获得所需的输出,一直到管道的末尾。但是,当 tomcat 服务器运行该命令时,它会生成一个空文件。调试文件 debug1
和 debug2
是预期的,但是 debug3
和之后是空的,这表明管道在 cut - f 1-2
(请参阅下面的更新 1)。
操作系统 - Fedora 22
java - openjdk 1.8.0_77
Tomcat - 7.0.39
sh --> bash - 4.3.42(1)-release
============================================= =================
更新 1:
这似乎不是cut
的问题。我写了一个简短的 python 脚本,cut.py
来实现与 cut -f 1-2
相同的功能(删除 '\t0.0'
从每一行的末尾开始)
import re, sys
myRE = re.compile( r'\s+0\.0$' )
for line in sys.stdin :
sys.stdout.write( myRE.sub( '', line ) )
使用 cut.py
代替 cut
,我遇到了同样的问题。对于服务器 debug3
及以后是空的,但如果我从日志复制粘贴到交互式 shell,一切正常。
============================================= =================
更新 2:
我还编写了一个简单的 bash 脚本来运行管道,以便 tomcat/java 只运行带有输入/输出文件名参数的 bash 脚本。如果我从交互式 shell 运行脚本,它会工作,但结果在 tomcat 中没有什么不同,在 shell 脚本中使用 cut
或 cut.py
。
最佳答案
在大多数系统上默认安装,Tomcat 没有与您的用户相同的环境。它不会运行,例如,您的 .bashrc .profile 或您在登录脚本中的任何内容,因此在您的用户 shell 环境中设置的所有变量都是不同的。
您可以通过将 env
命令与两个用户进行比较来检查这一点:您的用户以及通过您的 java 程序调用它,例如:
String[] textAnalysisPipeline = {"/bin/sh","-c","/usr/bin/env > /tmp/env.txt"}; //or wherever the 'env' command is in your system
Process process = Runtime.getRuntime().exec(textAnalysisPipeline);
...
并将 /tmp/env.txt
的内容与您的用户执行的 env
进行比较……它们可能非常不同。
寻找以下变量:
- 路径
- 类路径
- JAVA_HOME
我以前也遇到过同样的问题。我建议采用以下方法:
对一切使用绝对路径,包括对“java”、“tee”、“tail”和 libs(jar 文件)的调用...您在命令中;
更改 Tomcat 运行的环境配置以访问您在命令中调用的所有应用程序(通常通过调用配置所有必需的
PATH
变量的脚本(不要忘记JAVA_HOME
和CLASSPATH
到您的 jar 文件!)。检查 Startup.sh 和 Catalina.sh 以找到合适的位置来包含您的东西;更改您的命令以将错误输出重定向到不是消息中的
/dev/null
,而是重定向到您系统中某处您的应用程序可以写入的日志文件(通常/tmp/exec.log
就好了)所以你可以确定shell执行问题。我打赌它会是这样的:sh: ****: command not found
或Error: Unable to access jarfile
或您的应用程序无法定位的某些消息一个对象,因此您可以确定您在脚本中调用的应用程序不在PATH
环境变量中,或者您没有其中的库...通常都是
有关这方面的更多信息,请查看 https://www.mulesoft.com/tcat/tomcat-classpath
希望这有助于...
关于java - bash 命令在 tomcat/java Runtime.getRuntime.exec() 中失败,但可以从命令行运行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37784355/