xargs ne génère pas de command correcte

Je veux supprimer un certain nombre d'applications sur un appareil Android qui commencent toutes par le même package. Je les reçois avec la command suivante:

$ 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 

Maintenant je veux exécuter la adb uninstall pour chacun de ces noms de packages, j'ai pensé à utiliser 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 

On dirait que ça va marcher, alors je retire l' echo :

 $ adb shell ls /data/data | grep -i com.company | xargs -n1 adb uninstall Failure Failure Failure Failure Failure 

Cependant, exécuter chaque command génère un Success :

 $ adb uninstall com.company.android.app.adwidget Success 

Qu'est-ce que je fais mal?

Bien que le problème ait été causé par des caractères CR dans la sortie du adb shell (inséré par la discipline tty line du pty créé sur le système Android cible (voir ici pour plus de détails)), une autre explication possible il pour les lecteurs à venir que c'est un problème commun avec xargs ) aurait pu être que:

 adb shell ls /data/data | grep -i com.company | xargs -n1 adb uninstall 

en fonction de l'implémentation de xargs , le stdin d' adb sera soit /dev/null soit le pipe de grep . Dans tous les cas, ce ne sera pas le tty et c'est peut-être la raison adb laquelle adb échouera s'il espère pouvoir interagir avec l'user.

Avec GNU xargs et un shell xargs en charge la substitution de process (comme zsh ), vous pouvez le changer en:

 xargs -n1 -ra <(adb shell ls /data/data | grep -i com.company) adb uninstall 

Dans ce cas, xargs lit la list du file donné en argument à -a ce qui vous permet de ne plus utiliser stdin.

Ou puisque vous mentionnez zsh , vous pouvez utiliser:

 autoload zargs # best in ~/.zshrc zargs -L1 $(adb shell ls /data/data | grep -i com.company) -- adb uninstall 

(en utilisant -L au lieu de -n comme zargs -n limite le nombre total d'arguments à adb (y compris la uninstall ) ce qui signifie que nous aurions besoin de -n 2 ).

Ou utilisez simplement une boucle, qui serait encore plus courte et plus lisible dans ce cas:

 for x ($(adb shell ls /data/data | grep -i com.company)) adb uninstall $x 

Rediriger la sortie de l' adb shell ls /data/data | grep -i com.company de commands adb shell ls /data/data | grep -i com.company adb shell ls /data/data | grep -i com.company à un file et en l'examinant avec un hexeditor, j'ai découvert qu'ils sont ajoutés avec le return chariot de style Windows \r\n (0x0D 0x0A). Donc se débarrasser de la \r avec tr -d '\r' résolu le problème.

Commande entière utilisant for (de la réponse de Stéphane Chazelas ):

 for x in $(adb shell ls /data/data | grep -i com.company | tr -d '\r'); do adb uninstall $x; done 

Ou de manière similaire en utilisant xargs :

 adb shell ls /data/data | grep -i com.company | tr -d '\r' | xargs -r -n1 adb uninstall 

Une autre option (comme aimablement expliquée par Stéphane Chazelas sur les commentaires ci-dessous) est désactivée avec stty -opost , bien que cela nécessite probablement busybox (ou une alternative comme toybox ) pour être installé sur le périphérique Android.

 $ adb shell echo test | sed -nl test\r$ $ adb shell 'busybox stty -opost; echo test' | sed -nl test$