Is there a way to write a script that will copy files from an ADB shell using run-as?
The only way I know of to copy in the adb shell is using cat source > dest
(edit: modern android versions have the cp
command, which makes this question unnecessary), but I am only able to quote the greater-than sign one level deep - so my script can pass it to adb shell, but not to adb shell run-as.
For example, this works:
adb shell "cat source > dest"
But this does not:
adb shell run-as "cat source > dest"
Nor this:
adb shell "run-as cat source \> dest"
I even tried created a small script and uploading it to the device, but I can't seem to run the script from the adb shell - it tells me "permission denied". I can't chmod the script, either.
The reason I want to do this is to copy a file into an app's private storage area - specifically, I am using a script to modify shared preferences and put the modified preferences back. Only the app itself or root can write to the file I want, however.
The use case in this scenario is coping a file to a protected location on the device, not retrieving it; for retrieving, there are already good answers in this question.
you could just change the permission of the directory and then pull all the files out. but for me i was looking for just one shared preference file and i was able to get the data like this:
now we have the data of the sharedpreference file stored in a file of the same name.
The OP tried to combine the following 3 commands (that he had no problem executing one after another in the interactive shell session) into a single non-interactive command:
For simplicity let's start from within an interactive
adb shell
session. If we just try to combine the last two commands into a single line:This would not work because of how shell redirection works - only the
cat /sdcard/temp_prefs.xml
part of the command would be run withcom.example.app
UID
Many people "know" to put the part of the command around redirection into quotes:
This does not work because the
run-as
command is not smart enough to parse the whole command. It expects an executable as the next parameter. The proper way to do it would be to usesh
instead:So can we just prepend
adb shell
to the command and be done with it? Not necessarily. By running the command from your PC you also add another local shell and its parser. Specific escape requirements would depend on your OS. In Linux or OSX (if your command does not already contain any'
) it is easy to single-quote the whole command like so:But sometimes it is just easier to use an alternative solutions with (-out or less) quotes:
Or if your device does not have the
cp
command:Also notice how I used
shared_prefs/com.example.app_preferences.xml
instead of full/data/data/com.example.app/shared_prefs/com.example.app_preferences.xml
- normally inside ofrun-as
command your current directory is theHOME
dir of your package.Following Chris Stratton's advice, the way I eventually got this to work was as follows (for copying shared preferences back to the device):
Piping directly to
adb shell run-as
did not work, and I do not know why, but piping toadb shell
does. The trick is to then call run-as from the interactive shell, and it continues to accept input from the pipe.The HERE doc lets me easily embed the newlines to separate commands and in general just makes it readable; I did not have much luck with semicolons, but that might have been because of the way I was doing things. I believe it might work with other methods of piping multiple commands/newlines; I stopped the experiment once I finally got it to work.
The two exits are necessary to prevent a hanging shell (killable with CTRL-C); one for
run-as
, and the other foradb shell
itself. Adb's shell doesn't respond to end-of-file very nicely, it seems.