老哥们我有一个在 Linux 执行 Java Process 的问题

2023-05-25 22:34:36 +08:00
 DIO

我想将类似 ffmpeg -i “input.mkv” -i “input.chs&jpn.ass” -c copy "output/output1.mkv" 这样的命令由 Java 代码来执行

java

        List<String> command = new ArrayList<>();  
        command.add(ffmpegPath);  
        command.add("-i");  
        //输入视频文件 File
        command.add(file.getAbsolutePath());  
        command.add("-i");  
        //输入字幕文件 File
        command.add(sub.getAbsolutePath());  
        command.add("-c");  
        command.add("copy");  
        //拼接输出路径
        command.add((new File(out,fileName)).getAbsolutePath());

由于考虑多平台运行,所以路径获取和拼接都是通过 File ,没有自己加 Separate 。

在 windows 编译执行没问题,成功进行了分类

但是在 linux,总是执行失败

Log 以后,提示是这样的:

INFO: "/home/codeTest/ffmpegSubTest/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].mkv": No such file or directory 其实已经分好类了,也就是说 File 对象指向是符合我预期的,只是创建文件夹利用的是 Java File 类的 mkdirs ()。

那就是 ffmpeg 命令这里参数出了问题,我试过给参数再套一层双引号(""),同样是 win 编译执行 ok ,linux “No such file or directory”

请问如何处理参数问题,或者有更好的解决方案希望能赐教

java Process 在不同平台执行看了会源码没看太明白。

2093 次点击
所在节点    程序员
23 条回复
urnoob
2023-05-25 23:57:11 +08:00
文件名包含空格导致的吧
判断下平台,Linux 就给空格加转义
urnoob
2023-05-25 23:59:06 +08:00
或者把文件名用双引号包起来
CLMan
2023-05-26 00:01:45 +08:00
文件没找到就是特殊字符的原因,先一个个测试是否哪些字符导致的问题,在想办法从程序上,还是从修改文件名上解决问题。
DIO
2023-05-26 00:10:17 +08:00
@urnoob 双引号包起来亲测不可行,命令行直接用是奏效的。如果不用双引号包起来,命令行直接执行时就是割裂的。平台判断也加了。转义之前没尝试,因为不知道空格转义成什么,也不知道有没有什么其他字符需要处理。
msg7086
2023-05-26 00:10:44 +08:00
很高兴见到你下载我组作品。
建议你先把 command 的内容打印出来看看是不是符合预期。

“/home/codeTest/ffmpegSubTest/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].mkv” 这个文件真实存在吗?

双引号应该是不需要套的。
DIO
2023-05-26 00:15:43 +08:00
@msg7086 贵组字幕做的很好,其他有直接内嵌的但是翻译太差不想用于是想搞个工具 233 。command 在平台执行的具体内容可以打印出来吗,我在 ide 调试看不到转换后的内容。由于能力有限,查看源码也没搞清楚。
msg7086
2023-05-26 00:18:10 +08:00
@DIO 直接执行命令是不会被转义的,只有经过 shell 运行的时候才需要考虑转义(和双引号等 shell 会处理的符号)。
所以不存在转换后的内容一说,你填在 command 里的参数就是实际执行的参数。
DIO
2023-05-26 00:20:35 +08:00
@msg7086 文件是真实存在的,我的代码都是自动从当前目录扫描得到 file 的,我其实不会去手动输入任何路径。双引号我在参数里套过,但是照样是 win 符合预期执行,linux 不符合。相同的命令形式在两个平台测试,却是都能达到预期效果
DIO
2023-05-26 00:24:25 +08:00
@msg7086 如果说是按照数组形式,命令是否符合预期,是的,我在 LOG 以及 IDE 调试时都会查看 command 数组内容,参数均与预期一致
msg7086
2023-05-26 00:33:56 +08:00
你贴的错误日志应该是从 logger 输出的吧。logger.info()里的参数你填的是什么?以及有没有抓到任何 exception ?
ysc3839
2023-05-26 00:56:50 +08:00
@urnoob 你说 Windows 出错了这么做还有点道理。Windows 和 Unix 有个显著差异是,Windows 的进程命令行是一个字符串,而 Unix 的进程命令行是字符串数组。既然 Windows 只能传单个字符串,这其中就涉及空格转义问题了。理论上 Windows 程序可以用任意规则解析命令行,不过为了兼容 Unix ,是有提供一套标准的解析规则来解析成字符串数组的。而 Unix 进程拿到的就是字符串数组,解析工作是由 shell 进行的。如果是自己程序启动进程,那可以直接传递字符串数组,不需要转义。

至于楼主的问题,我比较怀疑是命令行写错了,建议给出一段最简单的可复现代码。
githmb
2023-05-26 01:39:04 +08:00
你是不是忽略了 & 在 Linux 下的作用?
ETiV
2023-05-26 01:51:17 +08:00
😂 恰恰是最关键的 [用什么去执行命令] 的代码没给出来
cslive
2023-05-26 08:44:38 +08:00
文件名有空格,在 linux 下识别不出来,将空格替换成下划线就可以了
DIO
2023-05-26 08:48:06 +08:00
@msg7086
## 我是简单把 list 转成字符串了

`code`
```
BindingContextFactory.LOGGER.info("command is"+command.toString());
```

'res'
```
INFO: command is[ffmpeg, -i, "/home/codeTest/ffmpegSubTest/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].mkv", -i, "/home/codeTest/ffmpegSubTest/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].jpn.ass", -c, copy, "/home/codeTest/ffmpegSubTest/output/jpn/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].mkv"]
```

## 另外就是简单的把 process 的流输出出来,能简单看到命令执行反馈
```
try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line = null;
while ((line = bufferedReader.readLine()) != null) {

BindingContextFactory.LOGGER.info(line);
}
} catch (IOException e) {
}
}).start();
```

## 然后 Exception 好像没有抓取到
DIO
2023-05-26 09:29:36 +08:00
@ysc3839 您好。我的代码已经 append 贴出。谢谢您
DIO
2023-05-26 09:30:41 +08:00
@ETiV

您好。我的代码已经 append 贴出。谢谢您
DIO
2023-05-26 09:35:49 +08:00
@githmb 我注意到 linux 目录下,带有&符号的目录会带单引号'',于是我尝试了判断系统类型,windows 加双引号或者不带,其他加单引号传参。还是 No such file or directory 。

接下来我会尝试转义&字符
感谢您,我在 append 中贴出代码链接,您什么时候有空希望能指教一二
yazinnnn
2023-05-26 09:36:02 +08:00
val command =
ProcessBuilder(
"ffmpeg",
"-i",
"/home/yazi/Downloads/[20230402]ん ⧸ YuuRi Cas\uD83E\uDD40.mp4",
"/home/yazi/Downloads/output.mp4"
).command()
println(command)
val process = Runtime.getRuntime().exec(command.toTypedArray())

用这个命令试了一下, 可以正常执行, 是不是你路径写错了?
msg7086
2023-05-26 09:40:24 +08:00
@DIO #15

[ffmpeg, -i, "/home/codeTest/ffmpegSubTest/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].mkv", -i, "/home/codeTest/ffmpegSubTest/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].jpn.ass", -c, copy, "/home/codeTest/ffmpegSubTest/output/jpn/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].mkv"]

双引号都删掉试试呢

[ffmpeg, -i, /home/codeTest/ffmpegSubTest/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].mkv, -i, /home/codeTest/ffmpegSubTest/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].jpn.ass, -c, copy, /home/codeTest/ffmpegSubTest/output/jpn/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].mkv]

变成这样应该就对了。

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/943015

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX