0

You can do adb shell pm list packages, and after reading through the list, do an adb shell pm path "com.yourpackage" to get the full path and do a simply adb pull.

Fact is: I want to automate this. I thought about a really simple bash script:

for apk in $(adb shell pm list packages | sed 's/package://g' | sort); do
    # If you just do an echo, IT WORKS
    # echo $apk
    # But here it doesn't work
    adb shell pm path $apk
done

But that simply doesn't work. It seems that "$apk" becomes lost or something and nothing is shown in that snippet. I don't know if it's a subshell problem, or some peculiarity when using variables that got through an adb shell.

Should I create a script apks.sh just using pm list, for and such, push it to my device, run adb shell only once and execute apks.sh?

  • Try enclosing the parameters in quotes: adb shell "pm path $apk" and see if that works. Quoting it such makes clear the entire thing should be passed to adb shell. Without the quotes, it's not clear whether the $apk is 2nd param to pm or 5th param to adb ;) – Izzy Mar 8 '16 at 6:49
  • The culprit is that pm list packages, just as pm path [PACKAGE], results in the output being preceded by the "package:" string. A way to circumvent this would be to iterate through the pm list packages with something like the following: for i in $(pm list packages); do. Then, inside the loop, you'll define a variable var with the content of i, such as in: var=$i. Next, you'll trim the "package:" with var="${var#p*:}", which will return the package name. After that, pass var through pm path, as in: pm path $var, and trim "package:" once more. – Death Mask Salesman Mar 8 '16 at 10:06
  • Regarding your question, I guess that the variable apk belongs to the Linux terminal only. At line 4, you're trying to pass apk to the pm as if it were an Android shell variable. – Death Mask Salesman Mar 8 '16 at 10:09
2

It doesn't work because adb is a nasty piece of work. For some reason, it deliberately adds carriage return in the output. You can read Gilles' answer for more info on that.

All of you've to do is delete the carriage return. Here's the tweaked script of yours:

IMG

You can use -p with adb pull if only you've version 1.0.32 or above of adb. You were using sort unnecessarily.

  • @Gilles is a f*king genius. Thanks for you as well! And for the sort... just eyecandy to be ordered on terminal. :) – Somebody still uses you MS-DOS Mar 9 '16 at 2:42
  • 1
    Good insight. However, the picture of the text is hard to read. If you edit your answer and replace the picture with the actual text, it'd work much better with SE. It'll make it substantially easier to read, plus it'll make the searches for resolutions easier to find your contribution. It'd also make it easier to copy and paste your example for testing. a solution that works. – L. D. James Jun 19 '17 at 7:17
2

I derived a one liner bash command from Firelord's awesome answer:

for package in $(adb shell pm list packages -3 | tr -d '\r' | sed 's/package://g'); do apk=$(adb shell pm path $package | tr -d '\r' | sed 's/package://g'); echo "Pulling $apk"; adb pull -p $apk "$package".apk; done

Changes/Improvements from original version:

  • Backups only 3rd party apps, coz I don't see the point of backing up built-in apps. However, if you wanna backup system apps too, just skip the -3 flag.
  • Renames all apks to their package names instead of overwriting the same base.apk package in Android 6.0 "Marshmallow" and above.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.