我想删除 Android 设备上的许多应用程序,它们都以相同的程序包开头。我使用以下命令获得这些:
$ adb shell ls /data/data | grep -i com.company
com.company.android.app.adwidget
com.company.android.app.attendancereports
com.company.android.app.atteventmanagement
com.company.android.app.buttonwidget
com.company.android.app.clockwidget
Run Code Online (Sandbox Code Playgroud)
现在我想对adb uninstall
这些包名中的每一个执行,我想到了使用xargs
:
$ adb shell ls /data/data | grep -i com.company | xargs -n1 echo adb uninstall
adb uninstall com.company.android.app.adwidget
adb uninstall com.company.android.app.attendancereports
adb uninstall com.company.android.app.atteventmanagement
adb uninstall com.company.android.app.buttonwidget
adb uninstall com.company.android.app.clockwidget
Run Code Online (Sandbox Code Playgroud)
看起来它会起作用,所以我删除了echo
:
$ adb shell ls /data/data | grep -i com.company | xargs -n1 adb uninstall
Failure
Failure
Failure
Failure
Failure
Run Code Online (Sandbox Code Playgroud)
但是,独立运行每个命令会产生Success
:
$ adb uninstall com.company.android.app.adwidget
Success
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?
虽然问题最终是由adb shell
输出中的 CR 字符引起的(由在目标 Android 系统上创建的 pty 的 tty 行规则插入(有关更多详细信息,请参见此处)),另一种可能的解释(我将其留在那里)对于未来的读者,因为这是 ) 的一个常见问题,xargs
可能是:
adb shell ls /data/data | grep -i com.company | xargs -n1 adb uninstall
Run Code Online (Sandbox Code Playgroud)
根据xargs
实现,adb
的标准输入将是/dev/null
或来自 的管道grep
。在任何情况下,它都不会是 tty,adb
如果它希望能够与用户交互,这可能是失败的原因。
使用 GNUxargs
和支持进程替换的 shell(如zsh
),您可以将其更改为:
xargs -n1 -ra <(adb shell ls /data/data | grep -i com.company) adb uninstall
Run Code Online (Sandbox Code Playgroud)
在这种情况下xargs
,从作为参数给出的文件中读取列表-a
,让您无需理会 stdin。
或者既然你提到了zsh
,你可以使用:
autoload zargs # best in ~/.zshrc
zargs -L1 $(adb shell ls /data/data | grep -i com.company) -- adb uninstall
Run Code Online (Sandbox Code Playgroud)
(使用-L
而不是-n
作为zargs
的-n
限制总数目的参数到adb
(包括uninstall
一个),我们将需要该装置-n 2
)。
或者简单地使用一个循环,在这种情况下它会更短更清晰:
for x ($(adb shell ls /data/data | grep -i com.company)) adb uninstall $x
Run Code Online (Sandbox Code Playgroud)
将输出重定向adb shell ls /data/data | grep -i com.company
到文件并使用十六进制编辑器检查它,我发现它们附加了 Windows 风格的回车符\\r\\n
(0x0D 0x0A)。所以摆脱\\r
withtr -d \'\\r\'
解决了问题。
整个命令使用for
(来自St\xc3\xa9phane Chazelas\' 的回答):
for x in $(adb shell ls /data/data | grep -i com.company | tr -d \'\\r\'); do adb uninstall $x; done\n
Run Code Online (Sandbox Code Playgroud)\n\n或者类似地使用xargs
:
adb shell ls /data/data | grep -i com.company | tr -d \'\\r\' | xargs -r -n1 adb uninstall\n
Run Code Online (Sandbox Code Playgroud)\n\n另一种选择(正如 St\xc3\xa9phane Chazelas 在下面的评论中所友好解释的那样)是\\r
完全禁用stty -opost
,尽管这很可能需要busybox
(或类似的替代方案toybox
在 Android 设备上安装
$ adb shell echo test | sed -n l \ntest\\r$\n$ adb shell \'busybox stty -opost; echo test\' | sed -n l\ntest$\n
Run Code Online (Sandbox Code Playgroud)\n