xargs not generating correct command
Though the problem ended up being caused by CR characters in the adb shell
output (inserted by the tty line discipline of the the pty created on the target Android system (see here for more details)), another possible explanation (and I'll leave it there for future readers as that's a common problem with xargs
) could have been that in:
adb shell ls /data/data | grep -i com.company | xargs -n1 adb uninstall
depending on the xargs
implementation, adb
's stdin will be either /dev/null
or the pipe from grep
. In any case, it won't be the tty and that may be why adb
fails if it expects to be able to interact with the user.
With GNU xargs
and a shell with support for process substitution (like zsh
), you could change it to:
xargs -n1 -ra <(adb shell ls /data/data | grep -i com.company) adb uninstall
In that case xargs
reads the list from the file given as argument to -a
which lets you leave stdin alone.
Or since you're mentioning zsh
, you could use:
autoload zargs # best in ~/.zshrc
zargs -L1 $(adb shell ls /data/data | grep -i com.company) -- adb uninstall
(using -L
instead of -n
as zargs
's -n
limits the total number of arguments to adb
(including the uninstall
one) which means we would need -n 2
).
Or simply use a loop, which would be even shorter and more legible in this case:
for x ($(adb shell ls /data/data | grep -i com.company)) adb uninstall $x
Redirecting the output of adb shell ls /data/data | grep -i com.company
to a file and examining it with a hexeditor I found out they're appended with Windows-style carriage return \r\n
(0x0D 0x0A). So getting rid of the \r
with tr -d '\r'
solved the problem.
Whole command using for
(from Stéphane Chazelas' answer):
for x in $(adb shell ls /data/data | grep -i com.company | tr -d '\r'); do adb uninstall $x; done
Or similarly using xargs
:
adb shell ls /data/data | grep -i com.company | tr -d '\r' | xargs -r -n1 adb uninstall
Another option (as kindly explained by Stéphane Chazelas on the comments below) is disabling \r
altogether with stty -opost
, although this most likely requires busybox
(or an alternative like toybox
) to be installed on the Android device.
$ adb shell echo test | sed -n l
test\r$
$ adb shell 'busybox stty -opost; echo test' | sed -n l
test$