我有一个tomcat,它在shell中运行一个进程,因为java中没有几个实用程序可用。--这段代码在其他机器上工作得很好,但是我的公共服务器上有一个神秘的问题。
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)。
OS - 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,结果没有什么不同。
发布于 2016-06-18 17:10:53
默认情况下,大多数系统上安装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执行的内容与用户进行比较.他们可能很不一样。
查找以下变量:
我过去已经有同样的问题了。我建议采取以下办法:
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环境变量中,或者您没有在其中包含哪些libs .通常都是有关此问题的其他信息,请参阅https://www.mulesoft.com/tcat/tomcat-classpath。
希望这能帮上忙。
发布于 2016-06-15 13:43:37
这主要是一个次要的或可能的解决办法,但您的管道可以大大简化。cat是无用,tail和cut可以用一个Awk脚本替换。
tee /tmp/debug1 <path/to/inputFile |
java -jar path/to/hfst-ol.jar path/to/analyser.ohfst 2>/dev/null |
tee /tmp/debug2 |
awk -F '\t' 'NR>5 { print $1 FS $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发布于 2016-06-15 12:16:02
您可以使用ProcessBuilder。使用单字符串形式的Runtime.exec不是一种好的样式.更好的选择是使用ProcessBuilder,自己拆分参数,而不是依赖Java为您拆分它们,这是非常天真的。
ProcessBuilder pb = new ProcessBuilder("/bin/bash", "-c", /*...*/);
pb.redirectErrorStream(true);
Process p = pb.start();https://stackoverflow.com/questions/37784355
复制相似问题