java - 从 Java 代码调用 shell 命令时无法获取输出

标签 java

我正在尝试按照 Mkyong 的说明通过 Java 代码调用 shell 命令.我的代码是:

public class ExecuteShellCommand {

    public static void main(){
        String absolutePath = "/home/marievi/Downloads/small.mp4";
        String command = "ffmpeg -i " + absolutePath;
        ExecuteShellCommand obj = new ExecuteShellCommand();
        String output = obj.executeCommand(command);
        System.out.println(output);
    }

    public String executeCommand(String command) {

        StringBuffer output = new StringBuffer();

        Process p;
        try {
            p = Runtime.getRuntime().exec(command);
            p.waitFor();
            BufferedReader reader =
                    new BufferedReader(new InputStreamReader(p.getInputStream()));

            String line = "";
            while ((line = reader.readLine()) != null) {
                output.append(line + "\n");
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return output.toString();
    }
}

但是我得到一个空的输出,并且只打印了一个换行符。但是,当我使用 Mkyong 运行代码时的例子:

public static void main(){
    ExecuteShellCommand obj = new ExecuteShellCommand();
    String domainName = "google.com";
    String command = "ping -c 3 " + domainName;
    String output = obj.executeCommand(command);
    System.out.println(output);
}

输出被打印出来。知道出了什么问题吗?当我直接执行命令时:

ffmpeg -i /home/marievi/Downloads/small.mp4

从命令行,我得到了想要的输出:

ffmpeg version 3.3.4-1~14.04.york1 Copyright (c) 2000-2017 the FFmpeg developers
  built with gcc 4.8 (Ubuntu 4.8.4-2ubuntu1~14.04.3)
  configuration: --prefix=/usr --extra-version='1~14.04.york1' --toolchain=hardened --libdir=/usr/lib/x86_64-linux-gnu --incdir=/usr/include/x86_64-linux-gnu --enable-gpl --disable-stripping --enable-avresample --enable-avisynth --enable-gnutls --enable-ladspa --enable-libass --enable-libbluray --enable-libbs2b --enable-libcaca --enable-libcdio --enable-libflite --enable-libfontconfig --enable-libfreetype --enable-libfribidi --enable-libgme --enable-libgsm --enable-libmp3lame --enable-libopenjpeg --enable-libmodplug --enable-libopus --enable-libpulse --enable-librubberband --enable-libshine --enable-libsnappy --enable-libsoxr --enable-libspeex --enable-libssh --enable-libtheora --enable-libtwolame --enable-libvorbis --enable-libvpx --enable-libwavpack --enable-libwebp --enable-libx265 --enable-libxvid --enable-libzmq --enable-libzvbi --enable-omx --enable-openal --enable-opengl --enable-sdl2 --enable-libdc1394 --enable-libiec61883 --enable-chromaprint --enable-frei0r --enable-libopencv --enable-libx264 --enable-shared
  libavutil      55. 58.100 / 55. 58.100
  libavcodec     57. 89.100 / 57. 89.100
  libavformat    57. 71.100 / 57. 71.100
  libavdevice    57.  6.100 / 57.  6.100
  libavfilter     6. 82.100 /  6. 82.100
  libavresample   3.  5.  0 /  3.  5.  0
  libswscale      4.  6.100 /  4.  6.100
  libswresample   2.  7.100 /  2.  7.100
  libpostproc    54.  5.100 / 54.  5.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/home/maxez/Downloads/small.mp4':
  Metadata:
    major_brand     : mp42
    minor_version   : 0
    compatible_brands: mp42isomavc1
    creation_time   : 2010-03-20T21:29:11.000000Z
    encoder         : HandBrake 0.9.4 2009112300
  Duration: 00:00:05.57, start: 0.000000, bitrate: 551 kb/s
    Stream #0:0(und): Video: h264 (Constrained Baseline) (avc1 / 0x31637661), yuv420p(tv, bt709), 560x320, 465 kb/s, 30 fps, 30 tbr, 90k tbn, 60 tbc (default)
    Metadata:
      creation_time   : 2010-03-20T21:29:11.000000Z
      encoder         : JVT/AVC Coding
    Stream #0:1(eng): Audio: aac (LC) (mp4a / 0x6134706D), 48000 Hz, mono, fltp, 83 kb/s (default)
    Metadata:
      creation_time   : 2010-03-20T21:29:11.000000Z

最佳答案

帮自己一个忙,避免依赖 mkyong.com。该站点只是重复您可以在公共(public)文档中轻松找到的内容,而不管它的建议有多糟糕或陈旧,也不管这些信息有多过时。

事实上,Runtime.exec 在过去 13 年里已经过时了。它的替代品是 ProcessBuilder,早在 Java 5 中就引入了。通过使用 ProcessBuilder,您可以允许将外部进程的错误输出显示在与 Java 程序的错误输出相同的位置。目前,您没有在任何地方展示它,因此无法知道哪里出了问题。

同样,StringBuffer 已经过时,非常古老;它的替代品是 StringBuilder。它们是相同的,除了 StringBuffer 有线程安全的额外开销,这很少有用。

此外,waitFor() 等待进程结束。显然,在阅读过程的输出之前,您不应该调用它。读取所有输出行后调用它。

最后,异常意味着“操作没有成功,你不应该像成功一样继续。”如果出现异常,则您的流程没有成功。由于读取流程的输出是您尝试执行的操作的基础,因此继续下去没有意义。相反,将任何捕获的异常包装在未经检查的异常中,如 RuntimeException。 (更好的选择是完全删除 try/catch,并将这些异常类型添加到 executeCommand 和 main 方法的 throws 子句中。)

public static void main() {
    String absolutePath = "/home/marievi/Downloads/small.mp4";
    String[] command = { "ffmpeg", "-i", absolutePath };
    ExecuteShellCommand obj = new ExecuteShellCommand();
    String output = obj.executeCommand(command);
    System.out.println(output);
}

public String executeCommand(String[] command) {

    StringBuilder output = new StringBuilder();

    try {
        ProcessBuilder builder = new ProcessBuilder(command);
        // Share standard input/output/error descriptors with Java process...
        builder.inheritIO();
        // ... except standard output, so we can read it with getInputStream().
        builder.redirectOutput(ProcessBuilder.Redirect.PIPE);

        Process p = builder.start();

        try (BufferedReader reader =
            new BufferedReader(new InputStreamReader(p.getInputStream()))) {

            String line = "";
            while ((line = reader.readLine()) != null) {
                output.append(line + "\n");
            }
        }

        p.waitFor();

    } catch (IOException | InterruptedException e) {
        // Process failed;  do not attempt to continue!
        throw new RuntimeException(e);
    }

    return output.toString();
}

关于java - 从 Java 代码调用 shell 命令时无法获取输出,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46405879/

相关文章:

java - Spring @Transactional 阻止 @Service 中的 @Autowired

java - linux/mac下用eclipse查询tomcat

java - 没有使用 JPQL join fetch 的 Hibernate session

java - 用 jsonpath 替换 json 值

java - 在 Safari 中, session 不会在后续的 POST 和 GET 之间保持

java - 不需要的静态变量

java - 使用httpclient时抛出OutOfMemoryError

java - 适用于 Windows 的 64 位版本的 Java 1.4.2?

java - 如何解决这个 Morphia 映射问题??? ---> 警告 [org.mongodb.morphia.mapping.DefaultCreator] - 未在 dbObj : 中找到定义的类

java - 除了节省代码行之外,lambda 表达式还有其他用途吗?