Java执行wmctrl命令获取Linux应用名称异常,求正确写法
解决Java执行带管道的wmctrl命令无效问题
问题核心在于Runtime.exec()不会自动解析Shell的管道符号|,它会把整个命令字符串当作单个程序执行,导致awk部分完全没被调用,自然返回wmctrl -l的完整输出。以下是两种可行的解决方式:
方法1:通过Shell执行完整命令
把命令交给系统Shell(如bash/sh)处理,让Shell解析管道符号。修改后的Java代码如下:
String str; Process p; try { // 用bash -c包裹完整命令,注意转义内部引号 String command = "bash -c \"wmctrl -l | awk '{$1=\\\"\\\"; $2=\\\"\\\"; $3=\\\"\\\"; print}'\""; p = Runtime.getRuntime().exec(command); BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream())); // 必须读取错误流,避免进程因缓冲区满阻塞 BufferedReader errBr = new BufferedReader(new InputStreamReader(p.getErrorStream())); while ((str = br.readLine()) != null) { activeWindowtitles.add(str); System.out.println(str); } // 输出错误信息用于调试(可选) String errStr; while ((errStr = errBr.readLine()) != null) { System.err.println(errStr); } p.waitFor(); p.destroy(); } catch (Exception ex) { ex.printStackTrace(); // 不要吞掉异常,方便排查问题 }
方法2:Java内部处理输出(无需依赖awk)
直接执行wmctrl -l,在Java代码中手动过滤每行的前三个字段,避免Shell转义的麻烦,同时更可控:
String str; Process p; try { String command = "wmctrl -l"; p = Runtime.getRuntime().exec(command); BufferedReader br = new BufferedReader(new InputStreamReader(p.getInputStream())); BufferedReader errBr = new BufferedReader(new InputStreamReader(p.getErrorStream())); while ((str = br.readLine()) != null) { // 按任意空白符分割,最多分成4部分,保留第4部分及之后的内容 String[] parts = str.split("\\s+", 4); if (parts.length >= 4) { String appName = parts[3]; activeWindowtitles.add(appName); System.out.println(appName); } } // 读取错误流 String errStr; while ((errStr = errBr.readLine()) != null) { System.err.println(errStr); } p.waitFor(); p.destroy(); } catch (Exception ex) { ex.printStackTrace(); }
关键注意点
- 不要空吞异常:原代码的空catch块会隐藏错误,改成打印堆栈信息才能快速排查问题。
- 必须读取错误流:进程的错误输出如果不读取,缓冲区满时会导致进程挂起,无法正常结束。
内容的提问来源于stack exchange,提问作者Ankush
相关产品推荐
相关产品推荐

