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$

Tags:

Xargs

Zsh