I am trying to run a shell script in my android board. It has android and I access via adb to the shell. After copying a simple .sh script, I have the following problems for running it.
Consecutive variables are not recognized. This does not work
PROJ_ON_SYS_PIN='1221'
echo $PROJ_ON_SYS_PIN> /sys/class/gpio/unexport
PROJ_ON_SYS_PIN_2='1222'
echo $PROJ_ON_SYS_PIN_2> /sys/class/gpio/unexport
But this alone works: echo 1221 > /sys/class/gpio/unexport
Enter seems strange behavior: Even refraining using variables this does not work, and is detected as a syntax error. I presume the return (skip line) in not working.
echo 1221> /sys/class/gpio/unexport
echo 1223> /sys/class/gpio/unexport
Is it related to the shell version?. Because I have been working with bash in linux quite a lot and never experienced this
Related
I use a Genymotion android emulator for my automated Xamarin UI tests through the bash commands.
The issue is that the emulator is killed by the test runner app after tests are done. So this causes some kind of corruption on the emulator's virtual device file, I suppose.
When I try to start the emulator next time using the same script, I get the following error from Genymotion:
After clicking the update button, Genymotion dashboard opens. Then I can run the emulator by double clicking. But, I cannot do these steps through the shell.
If I could figure out what Genymotion does to repair the emulator, I would do the same thing in the shell script.
Here is my script to run the GM emulator;
cd $HOME
emulatorId=$(VBoxManage list vms | grep -E -o -i "([0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12})" | shuf -n 1)
open -a /Applications/Genymotion.app/Contents/MacOS/player.app --args --vm-name $emulatorId
sleep 5
adb wait-for-device shell 'while [[ -z $(getprop sys.boot_completed) ]]; do sleep 1; done; input keyevent 82'
After this command is executed I run my tests like following;
dotnet test Droid.UI.test.dll
Any solution or workaround for skipping this prompt is highly appreciated,
Thanks!
Your script completely overrides the launchpad; that's the problem. Why not use gmtool? It has been designed especially for this type of use.
I'm trying to create a script to find and remove my app from the Android emulator through the adb shell.
This is what I've got:
adb shell "
cd data/app
for app in com.mycompany.*.apk;
do
echo $app
bundle=$(echo $app | sed 's/-[0-9]//g')
echo 'bundle name is $bundle'
if [ '$bundle' != '' ];then
adb uninstall $bundle
else
echo 'No apps found'
fi
done
exit
"
But it doesn't seem to work as expected.
my for loop doesn't iterate through anything. If I manually run the commands exactly as above in the shell, it works, but when I run it from a shellscript then the for loop doesn't see the files or anything. Although if I add an "ls", it prints the contents of the folder correctly... So;
echo $app prints nothing (an empty string) and;
echo 'bundle name is $bundle' prints bundle name is.
Therefore, it obviously never goes inside my if block, falling in to my else clause and that's it.
What am I doing wrong? I'm not very experienced in shell script, I'd appreciate any ideas.
My goal with this is to have a shell function that I can call to automate the process of removing my app from the emulator without having to drag it and uninstall it manually. Other ideas are also very much welcome.
Thanks!
You should not really go through the /data/app folder. If you want to uninstall multiple packages with names matching the com.mycompany pattern with a single adb command use:
adb shell "pm list packages com.mycompany | cut -c9- | xargs -n 1 sh /system/bin/pm uninstall"
I'm still curious to know why my approach was "suboptimal" and what
could I have done better?
Wild guess since I'm not familiar with adb shell but bash: Quotation. Variables can not be inside ticks '...$VAR' but "...$VAR". Anything inside ticks is taken "as is", i.e. literally:
echo 'bundle name is $bundle'
vs.
echo "bundle name is $bundle"
This question already has answers here:
Difference between sh and Bash
(11 answers)
Closed 1 year ago.
I'm trying to run linux shell script on adb shell. It's giving errors!
Here is the whole story:
I wrote a simple bash script hello.sh :
#!/bin/bash
function hello
{
echo "hello world!"
}
hello
running it as ./hello.sh produces the o/p
hello world!
Now I pushed the file to android device using
adb push hello.sh /data/folder_name
then ran following command to enter in adb shell
adb shell
In adb shell fired following commands
cd /data/folder_name
chmod 755 hello.sh
sh hello.sh
This is what I get on adb shell :
# sh hello.sh
sh hello.sh
function: not found
hello world!
hello: not found
#
What's happening here!
Or is there some different way to write function for adb shell script
I searched but didn't get proper solution
Please help.
Not sure about adb, but 'function' is not standard syntax. It is available in many shells, but the standard way to define a function is:
hello() { echo hello world; }
When invoked as sh, bash enters posix mode and it tries to mimic the startup behavior of historical versions of sh as closely as possible, while conforming to the POSIX standard as well.
The reserved word function is optional for bash, but I think is unknown to historical versions of sh.
Try to invoke the command as
bash /tmp/test.sh
You don't need to push the script to your phone - simply expand it in the shell itself like so and you save yourself time:
adb shell "$hello.sh"
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.
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:
adb shell
run-as com.example.app
cat /sdcard/temp_prefs.xml > shared_prefs/com.example.app_preferences.xml
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:
run-as com.example.app cat /sdcard/temp_prefs.xml > shared_prefs/com.example.app_preferences.xml
This would not work because of how shell redirection works - only the cat /sdcard/temp_prefs.xml part of the command would be run with com.example.app UID
Many people "know" to put the part of the command around redirection into quotes:
run-as com.example.app "cat /sdcard/temp_prefs.xml > shared_prefs/com.example.app_preferences.xml"
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 use sh instead:
run-as com.example.app sh -c "cat /sdcard/temp_prefs.xml > shared_prefs/com.example.app_preferences.xml"
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:
adb shell 'run-as com.example.app sh -c "cat /sdcard/temp_prefs.xml > shared_prefs/com.example.app_preferences.xml"'
But sometimes it is just easier to use an alternative solutions with (-out or less) quotes:
adb shell run-as com.example.app cp /sdcard/temp_prefs.xml shared_prefs/com.example.app_preferences.xml
Or if your device does not have the cp command:
adb shell run-as com.example.app dd if=/sdcard/temp_prefs.xml of=shared_prefs/com.example.app_preferences.xml
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 of run-as command your current directory is the HOME 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):
adb push shared_prefs.xml /sdcard/temp_prefs.xml
cat <<EOF | adb shell
run-as com.example.app
cat /sdcard/temp_prefs.xml > /data/data/com.example.app/shared_prefs/com.example.app_preferences.xml
exit
exit
EOF
Piping directly to adb shell run-as did not work, and I do not know why, but piping to adb 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 for adb shell itself. Adb's shell doesn't respond to end-of-file very nicely, it seems.
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:
PACKAGE='com.mypackage.cool'
SHAREDPREF_FILE="${PACKAGE}_preferences.xml"
adb shell "run-as $PACKAGE cat /data/data/$PACKAGE/shared_prefs/$SHAREDPREF_FILE">$SHAREDPREF_FILE
now we have the data of the sharedpreference file stored in a file of the same name.
Using the latest adb (ADB v1.0.41 / Version 33.0.3) and a Play Store emulator image I experienced adb root not being granted. I also could not copy from /data/local/ or /storage/emulated/0/ due to not having permissions when run-as com.myapp.app
new_prefs_path="my_machine.xml"
config="$(cat $new_prefs_path)"
my_app_uri="com.myapp.app"
adb shell "run-as $my_app_uri sh -c 'echo \"$config\" > shared_prefs/on_android.xml'"
This fixes it for me as a bash script. It's made slightly more complicated by needing to be configurable for different apps and complex payloads.
We take a file (could be generated earlier in this script) and read it to a variable.
We then start shell, do run-as my app and run echo expanding the read file to a file in shared_prefs.
I have file on SD-CARD and my app using it as log file.
Is it possible through the adb to watch file with all changes in real time?
Like with tail -f /sdcard/myfile.log command.
This seems to work great for me:
adb shell "while true; do cat; sleep 1; done < /sdcard/myfile.log"
You can install busybox and then:
adb shell
tail -f /path/of/your/file
But remember that you should have root access to install busybox. If you are using the emulator check this one:
How to get root access on Android emulator?
You can do this with logcat. You can add a view that will only show log entries from your app and it will be continuously updated.
There is a great app for this: Terminal IDE. It contains many linux commands, and it does not need root access. You can install it from GooglePlay. Is is free of charge (and open source, GPLv2).
One of its best features is that it can be used through telnet. Start it on your phone, and type telnetd command. It will start a telnet daemon, which listens on port 8080 by default.
After that you can connect it from your PC, with the following command: (use cygwin on windows)
telnet 192.168.1.8 8080
You should use your phone's IP address instead of the above one. After a successful connection you will have an arbitrary sized terminal on your PC, which is capable to run tail -f command on your phone. And many others, such as bash and all of its builtin commands.
Building upon Jesse's answer, to do similar with a file within an app's private storage area:
adb shell "while true; do run-as com.yourdomain.yourapp cat /data/data/com.yourdomain.yourapp/app_flutter/yourfile.txt; sleep 5; done" | egrep -o 'sometext.{0,50}'
(This example is for a flutter app on Android, but is similar minus the app_flutter directory.)
do run-as changes the user under which the command is run to the application. By default adb shell user shouldn't have access to any files under an application's private storage area.
| egrep -o 'sometext.{0,50}' the cat command sends the file contents to STDOUT. egrep is taking the contents & searching for -o (only) sometext + 50 characters" using regex (hence egrep instead of grep).
Last Line Only
Replace cat with tail -n 1.
Add --line-buffered to egrep
adb shell "while true; do run-as com.yourdomain.yourapp tail -n 1 /data/data/com.yourdomain.yourapp/app_flutter/yourfile.txt; sleep 5; done" | egrep --line-buffered -o 'sometext.{0,50}'