Java执行命令在代码中不起作用 [英] Java execute command doesn't work in code

查看:52
本文介绍了Java执行命令在代码中不起作用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在Java程序中调用java.lang.Runtime.exec(...)来运行简单传递给我的函数的命令(某些 FFMPEG 命令):

 私有静态void RunCommand(字符串命令)抛出InterruptedException {尝试 {//执行命令进程proc = Runtime.getRuntime().exec(command);}} 

对于简单的FFMPEG情况,例如 ffmpeg -i input.avi -c copy output.avi ,它运行正常.

但是对于其中一个命令,显然它没有运行.当我在命令行中复制/粘贴确切的String时,我可以运行它并查看输出文件.

  ffmpeg -i"concat:/home/temp10.avi |/home/p2.avi |/home/temp15.avi" -c复制-y/home/output.avi 

代码中有以下内容:

 字符串c4 ="ffmpeg -i \" concat:"+ dir + temp1 +" |"+ dir + ad +" |"+ dir + temp3 +" \"-c复制-y" + dir + output; 

这是怎么回事?有人猜测为什么它不能在代码中运行吗?如果"引起了问题,为什么相应的字符串看起来不错?!

解决方案

您编写的命令:

  ffmpeg -i"concat:/home/temp10.avi |/home/p2.avi |/home/temp15.avi" -c复制-y/home/output.avi 

在由shell运行时有效.引号是shell语法的一部分,而不是ffmpeg语法的一部分.由于 | 字符的缘故,必须进行报价,如果不加引号,它会导致外壳建立管线.引用时,将其简单地传递给ffmpeg.

您想使用java运行时 exec 函数完成相同的操作,但是 exec 并不像shell.它不执行管道,重定向,引号或 $ variable 替换.它在空白处分割字符串,并与生成的字符串数组等效于Unix execvp .

由于 exec 不会对 | 字符执行任何特殊操作,因此无需引用.传递给exec以完成与上述shell命令相同的操作的字符串应该只是

  ffmpeg -i concat:/home/temp10.avi |/home/p2.avi |/home/temp15.avi -c复制-y/home/output.avi 

根据文件名,可能会遇到麻烦.假设您的shell命令如下所示:

  ffmpeg -i"concat:/home/temp 10.avi |/home/p2.avi |/home/temp15.avi" -c复制-y/home/output.avi 

(区别:第一个文件名 temp 10.avi 中有一个空格.)现在,该引用有两个用途:防止 | 创建管道,并防止空格分割参数.如果您尝试在删除引号的情况下将其传递给 exec ,它将无法工作,因为字符串将被拆分,从而生成以下参数数组:

  -iconcat:/home/temp10.avi |/home/p2.avi |/home/temp15.avi-C复制-y/home/output.avi 

那不是ffmpeg想要的;它想要在 -i 之后包含完整输入规范的单个字符串.您必须自己完成拆分字符串的工作,以便可以在参数中保留空格,如下所示:

  Runtime.getRuntime().exec(新的String [] {"ffmpeg",-一世","concat:/home/temp 10.avi |/home/p2.avi |/home/temp15.avi",-C",复制","-y","/home/output.avi"}) 

下面的注释中的示例如下

  Runtime.getRuntime().exec(新的String [] {"ffmpeg",-一世","sample.mp4",-一世","ad.mp4","-filter_complex","[0:v] trim = 0:15,setpts = PTS-STARTPTS [v0]; [1:v] trim = 0:5,setpts = PTS-STARTPTS [v1]; [0:v] trim = 20:30,setpts = PTS-STARTPTS [v2]; [v0] [v1] [v2] concat = n = 3:v = 1:a = 0 [out],-地图",[出去]","output.mp4"}) 

-filter_complex 之后的大字符串是单个参数,因为它在命令的Shell版本中被引用.它在外壳程序中没有" 之间的特殊字符,在Java中没有" 之间的特殊字符,因此无需修改即可工作.

I am calling java.lang.Runtime.exec(...) in my Java program to run a command (some FFMPEG commands) simply passed to my function:

    private static void RunCommand(String command) throws InterruptedException {
        try {
            // Execute command
            Process proc = Runtime.getRuntime().exec(command);
}
}

It runs OK for simple FFMPEG cases such as ffmpeg -i input.avi -c copy output.avi.

But for one of the commands, apparently it doesn't run. When I copy/paste the exact String in command line, I am able to run it and see the output file.

ffmpeg -i "concat:/home/temp10.avi|/home/p2.avi|/home/temp15.avi" -c copy -y /home/output.avi

Which is the following in code:

String c4="ffmpeg -i \"concat:"+dir+temp1+"|"+dir+ad+"|"+dir+temp3+"\" -c copy -y "+dir+output;

What is going on? Any guesses why it doesn't run in code? If the " is causing the problem, why the corresponding string looks good?!

解决方案

The command as you have written it:

ffmpeg -i "concat:/home/temp10.avi|/home/p2.avi|/home/temp15.avi" -c copy -y /home/output.avi

works when run by a shell. The quotation marks are part of the shell syntax, not part of the ffmpeg syntax. Quoting is necessary because of the | character, which cause the shell to build a pipeline if it was unquoted. When it is quoted, it is simply passed along to ffmpeg.

You want to accomplish the same thing with the java Runtime exec function, but exec isn't like a shell. It doesn't do pipelines, or redirections, or quoting, or $variable substitutions. It splits the string on whitespace and does the equivalent of a unix execvp with the resulting array of strings.

Since exec won't do anything special with the | character, there is no need for quoting. The string you pass to exec to accomplish the same thing as the above shell command should just be

ffmpeg -i concat:/home/temp10.avi|/home/p2.avi|/home/temp15.avi -c copy -y /home/output.avi

There is a complication you may run into depending on the filenames. Suppose your shell command looked like this:

ffmpeg -i "concat:/home/temp 10.avi|/home/p2.avi|/home/temp15.avi" -c copy -y /home/output.avi

(Difference: the first filename temp 10.avi has a space in it.) Now the quoting is serving 2 purposes: prevent the | from creating a pipeline, and prevent the space from splitting the argument. If you try passing this to exec with the quotation marks removed, it won't work because the string will be split, generating this array of arguments:

-i
concat:/home/temp
10.avi|/home/p2.avi|/home/temp15.avi
-c
copy
-y
/home/output.avi

and that's not what ffmpeg wants; it wants a single string after the -i containing the full input specification. You would have to do the job of splitting the string yourself, so you can leave the space in the argument, like this:

Runtime.getRuntime().exec(
  new String[] {
    "ffmpeg",
    "-i",
    "concat:/home/temp 10.avi|/home/p2.avi|/home/temp15.avi",
    "-c",
    "copy",
    "-y",
    "/home/output.avi"
  }
)

The example in the comment below looks like

Runtime.getRuntime().exec(
  new String[] {
    "ffmpeg",
    "-i",
    "sample.mp4",
    "-i",
    "ad.mp4",
    "-filter_complex",
    "[0:v]trim=0:15,setpts=PTS-STARTPTS[v0]; [1:v]trim=0:5,setpts=PTS-STARTPTS[v1]; [0:v]trim=20:30,setpts=PTS-STARTPTS[v2]; [v0][v1][v2]concat=n=3:v=1:a=0[out]",
    "-map",
    "[out]",
    "output.mp4"
  }
)

The large string after -filter_complex is a single argument because it's quoted in the shell version of the command. It has no characters in it that are special between "" in the shell, and no characters that are special between "" in Java, so it works without modification.

这篇关于Java执行命令在代码中不起作用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆