【问题标题】:How to access shell script output when it is executed from inside a Java code? [duplicate]从 Java 代码内部执行时如何访问 shell 脚本输出? [复制]
【发布时间】:2014-12-18 02:57:31
【问题描述】:

我需要从 Java 执行以下脚本并能够在控制台上查看结果。但是 echo 语句在控制台上不可见。在网上花了一些时间后,我明白我需要控制输入输出流才能做到这一点。但我没有获得使这成为可能所需的信息。

我在下面发布了脚本和 Java 语句:

脚本:

#!/bin/sh
echo "Hello World"
echo "$1 $2"
exit 0

Java 代码:

List<String> command = new ArrayList<String>();
command.add("sh");
command.add("sript.sh");
command.add("Technopath007");
command.add("Dennis");
ProcessBuilder builder = new ProcessBuilder(command);
Process process = builder.start();
BufferedReader is = new BufferedReader(new InputStreamReader(process.getInputStream()));
String line = "";
while ((line = is.readLine()) != null)
    System.out.println(line);       

关于该主题的现有线程似乎不起作用。

请让我知道我在这里缺少什么。提前致谢。

【问题讨论】:

  • 你能展示你实际使用的代码,而不仅仅是它复制的代码吗?
  • 前两个代码 sn-ps 是我正在使用的.. 我已经相应地编辑了问题
  • 可能是您调用了错误的脚本或从另一个工作目录调用?如果发生这种情况,您可能不会在输出流上得到任何东西,只会在错误流上得到任何东西。

标签: java shell inputstream outputstream processbuilder


【解决方案1】:

使用 BufferedReader

类似这样的:

BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()));
string line = "";
while ((line = reader.readLine()) != null)
    System.out.println(line);
reader.Close();

【讨论】:

  • 它不起作用。我试过这个。刚才又这样做了。
  • 我这台电脑上没有java编译器,所以我不能真正为你测试它。试着看看这个线程:stackoverflow.com/questions/3643939/…
  • 确保将我发布的代码放在以下行之前:process.waitFor(); process.waitFor() 可能只是被删除。当您真正希望程序做的是在新进程退出之前显示输出时,等待程序停止执行是没有意义的。
  • 运气好吗?你能让它工作吗?
【解决方案2】:

试试这个:

/** Execute a command where each parameter is in the string array. It is better to
 * do such a call this way because passing a single string to the java
 * Runtime.getRuntime().exec("single long string") method invokes StringTokenizer
 * to split the string into an array of strings and it does a poor job at it.
 *
 * I.e. The string:
 *    ksh -c "mkdir /tmp/test"
 *
 * is split thus:
 *
 *    ksh
 *    -c
 *    "mkdir
 *    /tmp/test"
 *
 * and then the shell interpreter complains about unmatched quotes.
 *
 * Returns a list which is whatever was put
 * on the stdout, followed by what was put on stderr.
 * @param exec the execution array, the first entry is the executable to run.
 * Don't forget that shell builtin command must be run within a shell.
 * @return The output list.
 */
public List executeExactCommand(String exec[])
{
    int exitCode   = 3;  // Assume we failed
    List execOutput = new ArrayList();

    String execCmd = "";
    int    i;

    for (i = 0; i < exec.length; ++i) {
        execCmd += (((i != 0) ? " " : "") + exec[i]);
    }

    try {
        Process p = Runtime.getRuntime().exec(exec);

        try {
            InputStream  is   = p.getInputStream();
            StringBuffer desc;
            int          chr = 0;

            while (chr >= 0) {
                desc = new StringBuffer(5192);
                chr  = is.read();

                for (i = 0; (i < 5192) && (chr >= 0) && (chr != '\n'); chr = is.read()) {
                    // Because of Bill Gates, everyone in the world has to
                    // process for a possible, useless, RETURN character.
                    if (chr != '\r') {
                        desc.append((char) chr);
                        ++i;
                    }
                }

                if ((chr >= 0) || (desc.length() != 0)) {
                    execOutput.add(desc.toString());
                }
            }

            is  = p.getErrorStream();
            chr = 0;

            while (chr >= 0) {
                desc = new StringBuffer(5192);
                chr  = is.read();

                for (i = 0; (i < 5192) && (chr >= 0) && (chr != '\n'); chr = is.read()) {
                    // Because of Bill Gates, everyone in the world has to
                    // process for a possible, useless, RETURN character.
                    if (chr != '\r') {
                        desc.append((char) chr);
                        ++i;
                    }
                }

                if ((chr >= 0) || (desc.length() != 0)) {
                    execOutput.add(desc.toString());
                }
            }

            exitCode = p.waitFor();

            if (withCommandTrace) {
                execOutput.add("execCmd = " + execCmd + " (" + exitCode + ")");
            }
        }
        catch (InterruptedException x) {
            System.err.println("Error command interupted, cmd='" + execCmd + "'");
            System.err.println("Caught: " + x);
            execOutput.add("Error command interupted, cmd='" + execCmd + "'");
            execOutput.add("" + exitCode);
        }
    }
    catch (IOException x) {
        // couldn't exec command
        System.err.println("Error executing command, command=" + execCmd);
        System.err.println("Caught: " + x);
        execOutput.add("Error executing command, cmd='" + execCmd + "'");
        execOutput.add("" + exitCode);
    }

    if (withCommandTrace) {
        for (i = 0; (execOutput != null) && (i < execOutput.size()); ++i) {
            System.out.println((String) execOutput.get(i));
        }
    }

    return execOutput;
}

你可以这样称呼它:

List eachOutputLines = executeExactCommand(["bash", "-c", "ls -la /"]);

【讨论】:

  • 在这段代码中有很多我不关心的事情:(1)不从并行线程中的流中读取,这在技术上是避免阻塞的要求; (2) 一次读取一个字节,无需缓冲; (3) 不处理 Unicode; (4)\r换行处理不当; (5) 缺乏仿制药; (6) 重复代码。
  • 要扩展第 (1) 点,您需要同时排空输入流和错误流,因为其中任何一个都可能填满其内部缓冲区。如果发生这种情况,该进程将阻塞。该程序可以随时写入 stdout 或 stderr,因此先从一个读取然后从另一个读取是不安全的。这并不常见,但如果一个程序要向 stderr 写入超过 4KB 左右的大小,则此代码可能会挂起。
  • 我同意,这不是很好的代码,它可以大大改进。它是为明确终止的可执行文件而编写的,如果他们向 stderr 写入任何内容,这是他们在退出之前写的最后一件事。
猜你喜欢
  • 2011-07-12
  • 2021-12-09
  • 2018-03-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-06
  • 2018-09-08
  • 2019-12-29
相关资源
最近更新 更多