解析adb shell输出的异常行为及无中间变量实现方案咨询
问题原因分析
你遇到的这个差异,核心原因是**adb shell命令会默认读取标准输入(stdin)**,而第一个脚本里的while read是通过管道获取输入的,此时整个管道的stdin会被adb shell pm clear命令“抢走”,导致read只能读到第一个包名,剩下的包名被adb shell当作输入直接输出,根本没进入循环处理。
具体拆解一下:
- 管道把三个包名传给
while read后,第一次循环read读到第一个包com.biblehub.biblehubapp,接着执行$adb shell pm clear $package——这个命令会打开stdin,把管道里剩下的两个包名当作自己的输入读取并打印出来,同时完成第一个包的清理(输出Success)。 - 之后
read没有更多内容可以读取,循环直接结束,所以剩下两个包完全没被处理。
而第二个脚本用中间变量的方式,for循环是直接遍历变量里的字符串(按空格分割),此时adb shell的stdin不会和循环的输入冲突,每个包都能被正确处理。
无需中间变量的解决方案
要解决这个问题,关键是避免adb shell和while read共享stdin,这里有两种常用的可行方法:
方法1:给adb shell加-n选项(禁用stdin读取)
adb shell提供了-n参数,会让命令不读取stdin,这样就不会抢走read的输入了:
$adb shell pm list packages $applicationPattern | $dos2unix | cut -d: -f2 | while read package do echo "=> Processing <$package> ..." $adb shell -n pm clear $package | $dos2unix done
方法2:用进程替换代替管道
进程替换会把命令的输出当作临时文件,让while read从这个文件读取输入,彻底避免stdin共享的问题:
while read package do echo "=> Processing <$package> ..." $adb shell pm clear $package | $dos2unix done < <($adb shell pm list packages $applicationPattern | $dos2unix | cut -d: -f2)
这两种方法都不需要中间变量,就能让每个包都被正确循环处理,输出效果和你用中间变量的版本完全一致。
内容的提问来源于stack exchange,提问作者SebMa
相关产品推荐
相关产品推荐

