java - bash 命令在 tomcat/java Runtime.getRuntime.exec() 中失败,但可以从命令行运行

标签 java linux bash shell tomcat

我有一个在 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 服务器运行该命令时,它会生成一个空文件。调试文件 debug1debug2 是预期的,但是 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 脚本中使用 cutcut.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

我以前也遇到过同样的问题。我建议采用以下方法:

  1. 一切使用绝对路径,包括对“java”、“tee”、“tail”和 libs(jar 文件)的调用...您在命令中;

  2. 更改 Tomcat 运行的环境配置以访问您在命令中调用的所有应用程序(通常通过调用配置所有必需的 PATH 变量的脚本(不要忘记JAVA_HOMECLASSPATH 到您的 jar 文件!)。检查 Startup.sh 和 Catalina.sh 以找到合适的位置来包含您的东西;

  3. 更改您的命令以将错误输出重定向到不是消息中的 /dev/null,而是重定向到您系统中某处您的应用程序可以写入的日志文件(通常/tmp/exec.log 就好了)所以你可以确定shell执行问题。我打赌它会是这样的:sh: ****: command not foundError: 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/

相关文章:

Linux Bash ... 如果时间 > 20 :00 then echo 'hello' fi

java - 从 TextInputDialog 将 Optional<String> 转换为 Integer 时出错

Java 和 SSH 希望从一个文件执行多个命令,跨另一个文件中的主机列表并将输出写入文件

java - 我怎样才能在 Hibernate 中做乘法关系?

java - 网页查看 Android 应用程序

linux - AWS EC2 : Moving/var to EBS

linux - 将 .so 文件插入到 unix 上的 common-auth 文件中

c# - 在 Linux/Ubuntu 上部署 sql+winforms 应用程序,开发服务器仍然是 Windows

macos - 在 Mac OS X 上仅在关机时运行脚本(不是注销或重新启动)

git - .gitconfig 不遵循默认编辑器命令的 bash 别名?