为何同一条root权限的logcat+grep命令在终端可用但APP中生成空文件?
问题排查与解决方案
嘿,这个问题我之前做类似工具的时候也踩过坑,咱们来聊聊问题出在哪以及怎么解决~
核心原因
你在终端模拟器里能正常执行,是因为终端本身就是一个交互式的shell环境,它会自动解析命令里的管道(|)和重定向(>)这些特殊符号。但在APP里直接通过Runtime.exec("su")然后写命令的时候,默认情况下su并不会启动完整的shell来处理这些元字符——它只会把你写入的内容当作单个命令执行,根本没识别到|是管道,自然也就不会调用grep来筛选内容,最后生成的文件当然是空的。
而不带grep的logcat > 文件能生效,是因为部分设备的su实现会处理简单的重定向符号,但管道这种需要多进程协作的操作,必须依赖shell来解析才行。
解决办法
核心思路就是让su通过shell来执行整个命令,让shell帮我们解析管道和重定向。这里有两种实现方式:
方式1:直接用su的-c参数
su的-c参数可以让它直接调用shell执行指定的命令字符串,这样整个带管道的命令会被shell正确解析:
try { // 注意Java字符串里的双引号需要用\\转义 Process p = Runtime.getRuntime().exec("su -c \"logcat | grep --line-buffered \\\"search string\\\" > /storage/emulated/0/logcat.log\""); // 如果需要等待命令执行完成(比如非持续输出场景),可以加上waitFor() // p.waitFor(); } catch (IOException | InterruptedException e) { e.printStackTrace(); }
方式2:在su内部调用sh来执行命令
如果有些设备的su对-c参数支持不好,也可以在su之后手动启动sh来处理命令:
try { Process p = Runtime.getRuntime().exec("su"); DataOutputStream dos = new DataOutputStream(p.getOutputStream()); // 用sh -c包裹整个命令,让shell解析管道和重定向 dos.writeBytes("sh -c \"logcat | grep --line-buffered \\\"search string\\\" > /storage/emulated/0/logcat.log\"\n"); dos.flush(); dos.close(); // p.waitFor(); } catch (IOException | InterruptedException e) { e.printStackTrace(); }
额外排查小技巧
如果还是有问题,可以试试这两个小方法:
- 用
grep的绝对路径:有些设备上grep可能在/system/bin/grep,把命令里的grep改成/system/bin/grep,避免找不到命令的问题。 - 重定向错误输出:在命令末尾加上
2>&1,把错误信息也写入日志文件,比如:
这样如果su -c "logcat | grep --line-buffered \"search string\" > /storage/emulated/0/logcat.log 2>&1"grep或者logcat有错误,就能在日志里看到具体问题了。
内容的提问来源于stack exchange,提问作者1nikolas
相关产品推荐
相关产品推荐

