xargs não está gerando o comando correto

7

Eu quero excluir vários aplicativos em um dispositivo Android que começam com o mesmo pacote. Eu recebo estes com o seguinte comando:

$ 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

Agora quero executar adb uninstall para cada um desses nomes de pacote, pensei em usar 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

Parece que vai funcionar, então eu removo echo :

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

No entanto, a execução de cada comando gera, de forma independente, Success :

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

O que estou fazendo de errado?

    
por m0skit0 08.05.2017 / 13:21

2 respostas

4

Redirecionando a saída de adb shell ls /data/data | grep -i com.company para um arquivo e examinando-o com um hexeditor, descobri que eles estão anexados com o retorno de carro no estilo do Windows \r\n (0x0D 0x0A). Então, se livrar do \r com tr -d '\r' resolveu o problema.

Comando completo usando for (de resposta 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 similarmente usando xargs :

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

Outra opção (como explicado gentilmente por Stéphane Chazelas nos comentários abaixo) é a desativação de \r juntamente com stty -opost , embora isso provavelmente exija que busybox (ou uma alternativa como toybox ) seja instalado no Dispositivo Android.

$ adb shell echo test | sed -n l               
test\r$
$ adb shell 'busybox stty -opost; echo test' | sed -n l
test$
    
por 08.05.2017 / 16:07
8

Embora o problema tenha sido causado por caracteres CR no adb shell output (inserido pela disciplina de linha tty do arquivo criado no Android de destino sistema (veja aqui para mais detalhes)), outra explicação possível (e eu deixarei para os futuros leitores como esse é um problema comum com xargs ) poderia tem sido isso em:

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

dependendo da implementação de xargs , o stdin de adb será /dev/null ou o canal de grep . Em qualquer caso, não será o tty e pode ser por isso que adb falha se espera poder interagir com o usuário.

Com o GNU xargs e um shell com suporte para substituição de processo (como zsh ), você pode alterá-lo para:

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

Nesse caso, xargs lê a lista do arquivo fornecido como argumento para -a , o que permite que você deixe o stdin sozinho.

Ou, como você está mencionando zsh , pode usar:

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

(usando -L em vez de -n como zargs -n limita o número de argumentos total para adb (incluindo uninstall one) o que significa que precisaria de -n 2 ).

Ou simplesmente use um loop, que seria ainda mais curto e legível nesse caso:

for x ($(adb shell ls /data/data | grep -i com.company)) adb uninstall $x
    
por 08.05.2017 / 13:34

Tags