V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
DIO
V2EX  ›  程序员

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

  •  
  •   DIO · 2023-05-25 22:34:36 +08:00 · 2085 次点击
    这是一个创建于 542 天前的主题,其中的信息可能已经有所发展或是发生改变。

    我想将类似 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 编译执行没问题,成功进行了分类

    win 演示 1

    win 演示 2

    但是在 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 linux 其实已经分好类了,也就是说 File 对象指向是符合我预期的,只是创建文件夹利用的是 Java File 类的 mkdirs ()。

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

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

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

    第 1 条附言  ·  2023-05-26 09:28:00 +08:00

    老哥们这是我的代码,写的有点粗糙,轻喷。 点击访问代码

    额外需要的依赖这里下载 https://commons.apache.org/proper/commons-io/download_io.cgi

    第 2 条附言  ·  2023-05-26 10:01:54 +08:00
    问题解决了,谢谢大家
    23 条回复    2023-05-26 10:46:57 +08:00
    urnoob
        1
    urnoob  
       2023-05-25 23:57:11 +08:00 via Android
    文件名包含空格导致的吧
    判断下平台,Linux 就给空格加转义
    urnoob
        2
    urnoob  
       2023-05-25 23:59:06 +08:00 via Android
    或者把文件名用双引号包起来
    CLMan
        3
    CLMan  
       2023-05-26 00:01:45 +08:00
    文件没找到就是特殊字符的原因,先一个个测试是否哪些字符导致的问题,在想办法从程序上,还是从修改文件名上解决问题。
    DIO
        4
    DIO  
    OP
       2023-05-26 00:10:17 +08:00 via Android
    @urnoob 双引号包起来亲测不可行,命令行直接用是奏效的。如果不用双引号包起来,命令行直接执行时就是割裂的。平台判断也加了。转义之前没尝试,因为不知道空格转义成什么,也不知道有没有什么其他字符需要处理。
    msg7086
        5
    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
        6
    DIO  
    OP
       2023-05-26 00:15:43 +08:00 via Android
    @msg7086 贵组字幕做的很好,其他有直接内嵌的但是翻译太差不想用于是想搞个工具 233 。command 在平台执行的具体内容可以打印出来吗,我在 ide 调试看不到转换后的内容。由于能力有限,查看源码也没搞清楚。
    msg7086
        7
    msg7086  
       2023-05-26 00:18:10 +08:00
    @DIO 直接执行命令是不会被转义的,只有经过 shell 运行的时候才需要考虑转义(和双引号等 shell 会处理的符号)。
    所以不存在转换后的内容一说,你填在 command 里的参数就是实际执行的参数。
    DIO
        8
    DIO  
    OP
       2023-05-26 00:20:35 +08:00 via Android
    @msg7086 文件是真实存在的,我的代码都是自动从当前目录扫描得到 file 的,我其实不会去手动输入任何路径。双引号我在参数里套过,但是照样是 win 符合预期执行,linux 不符合。相同的命令形式在两个平台测试,却是都能达到预期效果
    DIO
        9
    DIO  
    OP
       2023-05-26 00:24:25 +08:00 via Android
    @msg7086 如果说是按照数组形式,命令是否符合预期,是的,我在 LOG 以及 IDE 调试时都会查看 command 数组内容,参数均与预期一致
    msg7086
        10
    msg7086  
       2023-05-26 00:33:56 +08:00
    你贴的错误日志应该是从 logger 输出的吧。logger.info()里的参数你填的是什么?以及有没有抓到任何 exception ?
    ysc3839
        11
    ysc3839  
       2023-05-26 00:56:50 +08:00 via Android
    @urnoob 你说 Windows 出错了这么做还有点道理。Windows 和 Unix 有个显著差异是,Windows 的进程命令行是一个字符串,而 Unix 的进程命令行是字符串数组。既然 Windows 只能传单个字符串,这其中就涉及空格转义问题了。理论上 Windows 程序可以用任意规则解析命令行,不过为了兼容 Unix ,是有提供一套标准的解析规则来解析成字符串数组的。而 Unix 进程拿到的就是字符串数组,解析工作是由 shell 进行的。如果是自己程序启动进程,那可以直接传递字符串数组,不需要转义。

    至于楼主的问题,我比较怀疑是命令行写错了,建议给出一段最简单的可复现代码。
    githmb
        12
    githmb  
       2023-05-26 01:39:04 +08:00
    你是不是忽略了 & 在 Linux 下的作用?
    ETiV
        13
    ETiV  
       2023-05-26 01:51:17 +08:00 via iPhone
    😂 恰恰是最关键的 [用什么去执行命令] 的代码没给出来
    cslive
        14
    cslive  
       2023-05-26 08:44:38 +08:00
    文件名有空格,在 linux 下识别不出来,将空格替换成下划线就可以了
    DIO
        15
    DIO  
    OP
       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
        16
    DIO  
    OP
       2023-05-26 09:29:36 +08:00
    @ysc3839 您好。我的代码已经 append 贴出。谢谢您
    DIO
        17
    DIO  
    OP
       2023-05-26 09:30:41 +08:00
    @ETiV

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

    接下来我会尝试转义&字符
    感谢您,我在 append 中贴出代码链接,您什么时候有空希望能指教一二
    yazinnnn
        19
    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
        20
    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]

    变成这样应该就对了。
    msg7086
        21
    msg7086  
       2023-05-26 09:45:20 +08:00
    Linux 下,Shell 才是负责转义的,包括空格,&,[],等等,都只有在经过 Shell 的时候(比如 bash -c ,或者在命令行提示符下运行时)。

    直接从 Java 调用 syscall 运行的时候加双引号是错误的行为。

    我想这也是为什么你一开始的提示里

    "/home/codeTest/ffmpegSubTest/[Kamigami&VCB-Studio] Boku dake ga Inai Machi [01][Ma10p_1080p][x265_flac_ac3].mkv": No such file or directory

    会有双引号的原因。因为你这样写的话就是要寻找 [.] / ["] / [home] 这个目录了。
    DIO
        22
    DIO  
    OP
       2023-05-26 10:00:37 +08:00
    @msg7086 感谢您,他好像开始工作了。昨天可能是头疼所以把转义字符去掉以后忘记修改代码到 NAS 。
    loginv2
        23
    loginv2  
       2023-05-26 10:46:57 +08:00
    简化输入文件名 使用绝对目录定位。我记得 ffmpeg 以前我载入 ass 文件的时候 相对路径总出错 不知道是我用的不对 还是怎么样
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1235 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 23:44 · PVG 07:44 · LAX 15:44 · JFK 18:44
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.