【问题标题】:Java not running shell scriptJava没有运行shell脚本
【发布时间】:2013-07-25 21:01:53
【问题描述】:

我有一个 java 代码,它获取一个数据文件,将数据复制到 perl 脚本,并从 shell 脚本调用 perl 脚本。以下是相关代码:

    public String returnStringForPerlScript(ArrayList<String> arrayContainingPerlScriptArguments, String singularFilePath) throws IOException{
    String argFileName = null;//5
    String argParsedFileName = null;//
    argParsedFileName = arrayContainingPerlScriptArguments.get(4);
    argFileName = arrayContainingPerlScriptArguments.get(5);
    System.out.print("ARG1: "+argFileName);
    System.out.print(" ARG2: "+argParsedFileName);

    String runCmdString = singularFilePath+"perlscript.pl";
    String runCmd  = singularFilePath+"runPerlScript.sh";


    return runCmd;
}

上面的代码是一个单独的类中的方法。下面的代码是 Process 实际初始化和运行的地方。

p = dfp.returnStringForPerlScript(perlParam, singularDirectoryPath);
System.out.println("Running from: "+p);
process = Runtime.getRuntime().exec(p);

令人困惑的是,这段代码之前运行得很好,而我改变的只是输出目录。我写了一个完全不同的文件路径,而不是“singularDirectoryPath”。我很困惑,因为我不知道代码有什么问题,考虑到它之前运行过。当我从终端调用“runPerlScript.sh”时,它起作用了。

我还应该补充一点,我确实尝试使用 String[] 而不是字符串,如下所示:

    String[] cmdArray = {"/bin/tcsh","-c","/filepath/runPerlScript.sh"};
    Process p = Runtime.getRuntime().exec(cmdArray);

仍然没有生成任何输出文件。

【问题讨论】:

  • shell 脚本或 perl 脚本都不是真正的可执行文件。他们依赖于一个 shell,这与 exec() 无关。
  • 当你说它不起作用时,它实际上做了什么?它会抛出错误吗?如果是,您可以添加堆栈跟踪吗?还请描述它曾经作为参数的值(当它工作时),你现在更改的新值是什么,打印语句的输出会很好
  • @c.s 抱歉,我应该更具体一些。我的意思是,当我说它不起作用时,我将它与生成输出文件时与现在未生成输出文件时进行比较。之前,当我调用 shell 脚本时,会生成许多输出文件。现在,当我调用 shell 脚本时,不会生成任何输出文件。此外,不会引发任何错误。我更改的唯一值是“singularDirectoryPath”,它基本上只是更改了应该调用 runPerlScript.sh 脚本的目录。
  • @BrianRoach 一个脚本可以直接被java调用,它只需要有适当的权限并且在第一行有对其解释器的引用

标签: java


【解决方案1】:

验证两件事:

    1234563 /p>
  • 您移动的文件必须具有可执行权限,使用 .chmod 755 myFile 之类的内容进行更改。

【讨论】:

  • 我确实确定了这一点。我有通过调用 chmod 777 更改文件权限的方法。它工作得很好。此外,perl 脚本有 #!/usr/bin/perl 行,我的 shell 有 #!/bin/bash
【解决方案2】:

您陈述问题的方式似乎无法解决。由于这曾经显然可以工作,因此有两件事发生了变化:您的 java 执行环境或您的操作系统环境(这就是为什么首先想到文件权限的原因)。

由于您可以手动执行脚本,因此最可能的原因似乎是 java 出于某种原因无法执行脚本。

请将以下代码添加到您的 java 程序中,并检查操作系统返回的退出代码是什么。

System.out.println("Waiting for process to finish...");
process.waitFor(); // wait until the process finishes
int exitCode = process.exitValue();
System.out.println("Process exit code: " + exitCode); 

编辑: 在 cmets 中提供的说明之后,最可能的情况是 Java 错误地传递了脚本的命令行参数。测试起来相对容易:只需在您的 shell 脚本命令 echo $1 $2 $3 的第一行添加尽可能多的参数即可。这样,您将确定参数是否正确传递。如果不是,那么问题出在 Java 端,我们应该使用 exec() 的 String[] 版本。我习惯了Processbuilder,所以我将在我的示例中使用它(请在执行上述测试后使用下面的代码,以便我们知道缺少哪些参数):

String shellScript = "/some/path/runPerlScript.sh";
String perlScript = "/some/path/perlscript.pl";

// similar to using exec() version with String[]
ProcessBuilder pb = new ProcessBuilder(shellScript , perlScript); 

// print what the process will see as current directory
File workDir = pb.directory();
System.out.println("Working directoy:" + workDir.getAbsolutePath());

// print the environment variables visible to the process
Map<String, String> env = pb.environment(); 
System.out.println("Environment available to shell script:\n" + env);

// set the working directory if needed depending on the output of the workDir above
pb.directory(new File("/some/path")); 
Process p = pb.start();

// add the lines from the previous snipet here that waits until the process is done

【讨论】:

  • 退出值为0,不代表正常终止吗?
  • @JeremyFisher 是的,这表明执行成功。请检查 a) 如果单独运行,您的脚本是否会向控制台输出任何输出?我的意思是你在上面的“等待进程完成......”和“进程退出代码:”之间看到了什么吗?如果没有,请在其中添加一个 echo 语句作为第一个命令。 b)如果您将脚本移动到其原始位置,它是否仍然像以前那样从 java 成功执行?
  • 我将 shell 脚本的输出重定向到控制台。奇怪的是,我的 shell 脚本中的 echo 语句被打印到控制台。此外,来自 Perl 脚本的打印语句也会打印到控制台。这表明 Java 正在调用调用 perl 脚本的 shell 脚本,但 perl 脚本似乎没有找到任何参数。此外,它现在正在生成错误代码 255。
  • 另外,如果我从终端调用shell脚本,不管它在哪个目录,它仍然能够很好地运行。 Java 和 Unix 之间的某些东西显然不起作用。
  • @JeremyFisher 请检查我在答案中的编辑。我建议您从现在开始使用终端进行所有测试(包括 java 程序)
【解决方案3】:

我查看了一些 Javadocs,并为我的问题想出了这个解决方案。不知道它为什么有效,但它有效!

    ProcessBuilder builder = new ProcessBuilder(p1);

        builder.directory(dirFile);
        Process process = builder.start();
        System.out.println("Process working directory: "+builder.directory().getAbsolutePath());
        InputStream is = process.getInputStream();
        InputStreamReader reader = new InputStreamReader(is);
        Scanner scan = new Scanner(reader);


        while(scan.hasNextLine()){
            System.out.println(scan.nextLine());
        }

基本上,我只是指定了 ProcessBuilder 的工作目录。我还将 String[] 传递给 ProcessBuilder 而不是字符串,并在我的字符串数组中指定了我的 shell。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-08
    相关资源
    最近更新 更多