feat(shell): add "madb shell" command

This adds "madb shell" command, which is a shorthand syntax for
"madb exec shell", which is an expected feature from most users.

Change-Id: I51a4d03d87c8f227f19114773f2f9d29408e620f
Ref: #27
diff --git a/doc.go b/doc.go
index bea4b64..8db83cc 100644
--- a/doc.go
+++ b/doc.go
@@ -20,6 +20,8 @@
                concurrently
    install     Install your app on all devices
    name        Manage device nicknames
+   shell       Run the provided adb shell command on all devices and emulators
+               concurrently
    start       Launch your app on all devices
    stop        Stop your app on all devices
    uninstall   Uninstall your app from all devices
@@ -327,6 +329,30 @@
    '@' sign followed by the index of the device in the output of 'adb devices'
    command, starting from 1. Command will be run only on specified devices.
 
+Madb shell - Run the provided adb shell command on all devices and emulators concurrently
+
+Runs the provided adb shell command on all devices and emulators concurrently.
+
+This command is a shorthand syntax for 'madb exec shell <command...>'. See 'madb
+help exec' for more details.
+
+Usage:
+   madb shell [flags] <command>
+
+<command> is a normal adb shell command, which will be executed on all devices
+and emulators.
+
+The madb shell flags are:
+ -d=false
+   Restrict the command to only run on real devices.
+ -e=false
+   Restrict the command to only run on emulators.
+ -n=
+   Comma-separated device serials, qualifiers, device indices (e.g., '@1',
+   '@2'), or nicknames (set by 'madb name'). A device index is specified by an
+   '@' sign followed by the index of the device in the output of 'adb devices'
+   command, starting from 1. Command will be run only on specified devices.
+
 Madb start - Launch your app on all devices
 
 Launches your app on all devices.
diff --git a/exec.go b/exec.go
index 9cf8c4d..32eecc1 100644
--- a/exec.go
+++ b/exec.go
@@ -44,7 +44,31 @@
 `,
 }
 
+var cmdMadbShell = &cmdline.Command{
+	Runner: subCommandRunner{subCmd: runMadbShellForDevice},
+	Name:   "shell",
+	Short:  "Run the provided adb shell command on all devices and emulators concurrently",
+	Long: `
+Runs the provided adb shell command on all devices and emulators concurrently.
+
+This command is a shorthand syntax for 'madb exec shell <command...>'.
+See 'madb help exec' for more details.
+`,
+	ArgsName: "<command>",
+	ArgsLong: `
+<command> is a normal adb shell command, which will be executed on all devices and emulators.
+`,
+}
+
 func runMadbExecForDevice(env *cmdline.Env, args []string, d device, properties variantProperties) error {
+	return runAdbCommandForDevice(env, args, d, properties, false)
+}
+
+func runMadbShellForDevice(env *cmdline.Env, args []string, d device, properties variantProperties) error {
+	return runAdbCommandForDevice(env, args, d, properties, true)
+}
+
+func runAdbCommandForDevice(env *cmdline.Env, args []string, d device, properties variantProperties, isShellCmd bool) error {
 	sh := gosh.NewShell(nil)
 	defer sh.Cleanup()
 
@@ -56,7 +80,11 @@
 		expandedArgs[i] = expandKeywords(arg, d)
 	}
 
-	cmdArgs := append([]string{"-s", d.Serial}, expandedArgs...)
+	cmdArgs := []string{"-s", d.Serial}
+	if isShellCmd {
+		cmdArgs = append(cmdArgs, "shell")
+	}
+	cmdArgs = append(cmdArgs, expandedArgs...)
 	cmd := sh.Cmd("adb", cmdArgs...)
 	return runGoshCommandForDevice(cmd, d, false)
 }
diff --git a/madb.go b/madb.go
index 05572cc..e3b26a9 100644
--- a/madb.go
+++ b/madb.go
@@ -77,6 +77,7 @@
 		cmdMadbExec,
 		cmdMadbInstall,
 		cmdMadbName,
+		cmdMadbShell,
 		cmdMadbStart,
 		cmdMadbStop,
 		cmdMadbUninstall,