33

Is there a way of running adb commands on all connected devices? To uninstall an app from all connected devices with "adb uninstall com.example.android".

The commands I am interested in is mainly install and uninstall.

I was thinking about writing a bash script for this, but I feel like someone should have done it already :)

Heinrisch
  • 5,835
  • 4
  • 33
  • 43

6 Answers6

31

Create a bash file and name it e.g. adb+:

#!/bin/bash
adb devices | while read -r line
do
if [ ! "$line" = "" ] && [ "$(echo "$line" | awk '{print $2}')" = "device" ]
then
    device=$(echo "$line" | awk '{print $1}')
    echo "$device" "$@" ...
    adb -s "$device" "$@"
fi
done

Usage: ./adb+ <command>

msal
  • 947
  • 1
  • 9
  • 30
Oli
  • 3,496
  • 23
  • 32
  • Works great! Thanks! The only thing missing now is doing it in parallel :) – Heinrisch Jul 26 '13 at 14:24
  • 14
    `adb -s $device $@ &` will do in parallel – Diego Torres Milano Jul 26 '13 at 16:24
  • 2
    Should this work for adb shell commands? Works for 'adb+ root', but it seems to direct all commands into the first device shell for 'adb+ shell setenforce 0' – Habib Mar 21 '17 at 19:26
  • @Habib It seems the adb shell command will consume stdin, so you can use the shell -n option and the shell command will not consume the rest of stdin. Link to answer: https://stackoverflow.com/a/44634888/6454399 – Harold Henderson Mar 14 '18 at 18:39
12

Building on @Oli's answer, this will also let the command(s) run in parallel, using xargs. Just add this to your .bashrc file:

function adball()
{
    adb devices | egrep '\t(device|emulator)' | cut -f 1 | xargs -t -J% -n1 -P5 \
          adb -s % "$@"
}

and apply it by opening a new shell terminal, . ~/.bashrc, or source ~/.bashrc.

  1. If you only want to run on devices (or only on emulators), you can change the (device|emulator) grep by removing the one you don't want. This command as written above will run on all attached devices and emulators.
  2. the -J% argument specifies that you want xargs to replace the first occurrence of % in the utility with the value from the left side of the pipe (stdin).
    NOTE: this is for BSD (Darwin / Mac OS X) xargs. For GNU/Linux xargs, the option is -I%.
  3. -t will cause xargs to print the command it is about to run immediately before running it.
  4. -n1 means xargs should only use at most 1 argument in each invocation of the command (as opposed to some utilities which can take multiple arguments, like rm for example).
  5. -P5 allows up to 5 parallel processes to run simultaneously. If you want instead to run the commands sequentially, simply remove the entire -P5 argument. This also allows you to have two variations of the command (adball and adbseq, for example) -- one that runs in parallel, the other sequentially.

To prove that it is parallel, you can run a shell command that includes a sleep in it, for example:

$ adball shell "getprop ro.serialno ; date ; sleep 1 ; date ; getprop ro.serialno"

You can use this to run any adb command you want (yes, even adball logcat will work! but it might look a little strange because both logs will be streaming to your console in parallel, so you won't be able to distinguish which device a given log line is coming from).


The benefit of this approach over @dtmilano's & approach is that xargs will continue to block the shell as long as at least one of the parallel processes is still running: that means you can break out of both commands by simply using ^C, just like you're used to doing. With dtmilano's approach, if you were to run adb+ logcat, then both logcat processes would be backgrounded, and so you would have to manually kill the logcat process yourself using ps and kill or pkill. Using xargs makes it look and feel just like a regular blocking command line, and if you only have one device, then it will work exactly like adb.

Sebo
  • 443
  • 6
  • 14
Joe
  • 42,036
  • 13
  • 45
  • 61
  • Which version of xargs do you use? I don't find any documented version which includes the option -J%. Is there an alternative option? I would like to use adball with xargs on mingw/msys in context of msysgit (xargs GNU findutils version 4.4.2). – arne.jans Sep 23 '14 at 08:40
  • @CarlosSobrinho, thanks for that; tested and it appears you are correct on GNU/Linux. The `-I%` option is for BSD/Darwin/Mac OS X. I've edited the answer to clarify and give the GNU version. – Joe Nov 06 '14 at 20:41
  • @arne.jans, that^ should answer your question re -J :) – Joe Nov 06 '14 at 20:42
  • 1
    I've used an alias instead: `alias adball="adb devices | egrep '\t(device|emulator)' | cut -f 1 | xargs -t -J% -n1 -P5 adb -s % \"\$@\""` – gmazzo Feb 14 '17 at 02:19
  • Love this. Thanks for the detailed explanation! – Esdras Lopez Feb 01 '20 at 01:20
6

This is an improved version of the script from 強大な. The original version was not matching some devices.

DEVICES=`adb devices | grep -v devices | grep device | cut -f 1`
for device in $DEVICES; do
    echo "$device $@ ..."
    adb -s $device $@
done
Roberto Leinardi
  • 10,641
  • 6
  • 65
  • 69
4

To add in the ~/.bashrc or ~/.zshrc:

alias adb-all="adb devices | awk 'NR>1{print \$1}' | parallel -rkj0 --tagstring 'on {}: ' adb -s {}"

Examples:

  • $ adb-all shell date
  • $ adb-all shell getprop net.hostname
  • $ adb-all sideload /path/to/rom.zip
  • $ adb-all install /path/filename.apk
  • $ adb-all push /usr/local/bin/frida-server-arm64 /data/local/tmp/frida-server

Explanation: awk extracts the device id/host (first column: print $1) of every lines except the first one (NR>1) to remove the "List of devices attached" header line), then gnu parallel runs adb -s <HOSTNAME> <whatever-is-passed-to-the-alias> on whatever non-empty line (-r) in the order specified (-k, to avoid random order / fastest response order) and prepend each line with on <DEVICE>:\t for clarity, all in parallel (-j0, possible to set another number to define how many adb should be ran in parallel instead of unlimited).

:)

William
  • 41
  • 1
4

This is the highest result on Google, so for all Windows users coming here let me add this solution by User zingh (slightly modified to accept arbitrary commands, rather than "only" install

Batch file (adball.bat):

FOR /F "skip=1"  %%x IN ('adb devices') DO start adb -s %%x %*

Call as:

adball uninstall com.mypackage

(%* takes all input parameters, my line above makes it so that all commands are passed to adb as they are, so that you can type multiple words, flags etc.)

Note: you can even use this directly from the Android Studio "run all" popup, if you install the Powershell-plugin. You can add adball to your path, then double-tap ctrl and run

powershell adball uninstall com.mypackage
avalancha
  • 1,457
  • 1
  • 22
  • 41
1

adb wrapper supports selecting multiple targets for adb commands and parallel execution.

From its README:

# Installation
./install.sh ~/apps/android-sdk-linux
# Execute adb commands on all connected devices.
adb set-target all
# Execute adb commands on given devices.
adb set-target emulator-5554 C59KGT14263422
# Use GNU parallel for parallel install.
adb set-parallel true

(Disclaimer: I have written half of it)

Michał Zieliński
  • 1,345
  • 11
  • 13
  • Hi, downloaded and installed your tool. Trying to perform "adb set-target all" will issue an error: "adb: usage: unknown command set-target". Couldn't find any documentation in the link you attached. – Nisim Naim Nov 13 '18 at 11:52