String equality in Bash script [duplicate] - android

This question already has answers here:
How to compare strings in Bash
(12 answers)
Closed 8 years ago.
I want to simply test if an android device is rooted from a computer (for a root/backup/flash script).
So i have to test some locations for the su binary. Here is my code :
#!/bin/sh
#####################
## ROOT CHECK
SU_LOCATIONS="/system/bin/su /system/xbin/su"
check() {
echo "Checking for SU binary…"
for file in $SU_LOCATIONS
do
suFileResult=`$ADB shell "ls $file"`
echo "suFileResult = $suFileResult"
echo "file = $file"
if [ "$suFileResult" == "$file" ];
then echo "Su trouvé à $suFileResult"
fi
done
echo "$suFileResult" > tmpbak/suFil
}
The problem is that even if file == suFileResult, "if" return false. If i remove the spaces around ==, "if" will always return TRUE…
What am i doing wrong ? If you give an other way to test the file (and where), it would be perfect.
Thanks for your answers !
PS : the string could contain spaces here, such as :
/system/bin/su: No such file or directory
EDIT After answer :
By the way, i figured how to remove this annoying \r character : add
| tr -d '\r'
will remove this character in ALL the string (not only on the end). So in my case :
suFileResult=$(adb shell "[[ -e $file ]]; echo \$?;" | tr -d '\r')

By some weird reason adb returns strings with DOS line-ending (\r\n).
$ suFileResult="$(adb shell "ls $file")"
$ set | grep suFileResult
suFileResult=$'/system/bin/su\r'
So the proper condidtion statement may look like:
[[ $suFileResult == ${file}$'\r' ]]
Also, I should note that using ls for checking file existence is a quite odd approach, even though adb does not return an error code, you could print it to STDOUT:
suFileResult=$(adb shell "[[ -e $file ]]; echo \$?")
if [[ $suFileResult == $'0\r' ]]; then
echo "Su trouvé à $file"
fi

Related

Get application name from its package name via adb [duplicate]

I'm developing an application that uses ADB Shell to interface with android devices, and I need some way of printing out the application name or label of an application, given maybe their package name.
In short, I need a way of getting app names (i.e. "Angry Birds v1.0.0") for user installed applications through adb shell.
Any light on the matter? Any help is appreciated on this.
adb shell pm list packages will give you a list of all installed package names.
You can then use dumpsys | grep -A18 "Package \[my.package\]" to grab the package information such as version identifiers etc
just enter the following command on command prompt after launching the app:
adb shell dumpsys window windows | find "mCurrentFocus"
if executing the command on linux terminal replace find by grep
If you know the app id of the package (like org.mozilla.firefox), it is easy.
First to get the path of actual package file of the appId,
$ adb shell pm list packages -f com.google.android.apps.inbox
package:/data/app/com.google.android.apps.inbox-1/base.apk=com.google.android.apps.inbox
Now you can do some grep|sed magic to extract the path : /data/app/com.google.android.apps.inbox-1/base.apk
After that aapt tool comes in handy :
$ adb shell aapt dump badging /data/app/com.google.android.apps.inbox-1/base.apk
...
application-label:'Inbox'
application-label-hi:'Inbox'
application-label-ru:'Inbox'
...
Again some grep magic to get the Label.
A shell script to accomplish this:
#!/bin/bash
# Remove whitespace
function remWS {
if [ -z "${1}" ]; then
cat | tr -d '[:space:]'
else
echo "${1}" | tr -d '[:space:]'
fi
}
for pkg in $(adb shell pm list packages -3 | cut -d':' -f2); do
apk_loc="$(adb shell pm path $(remWS $pkg) | cut -d':' -f2 | remWS)"
apk_name="$(adb shell aapt dump badging $apk_loc | pcregrep -o1 $'application-label:\'(.+)\'' | remWS)"
apk_info="$(adb shell aapt dump badging $apk_loc | pcregrep -o1 '\b(package: .+)')"
echo "$apk_name v$(echo $apk_info | pcregrep -io1 -e $'\\bversionName=\'(.+?)\'')"
done
Inorder to find an app's name (application label), you need to do the following:
(as shown in other answers)
Find the APK path of the app whose name you want to find.
Using aapt command, find the app label.
But devices don't ship with the aapt binary out-of-the-box.
So you will need to install it first. You can download it from here:
https://github.com/Calsign/APDE/tree/master/APDE/src/main/assets/aapt-binaries
Check this guide for complete steps:
How to find an app name using package name through ADB Android?
(Disclaimer: I am the author of that blog post)
This is what I just came up with. It gives a few errors but works well enough for my needs, matching package names to labels.
It pulls copies of all packages into subdirectories of $PWD, so keep that in mind if storage is a concern.
#!/bin/bash
TOOLS=~/Downloads/adt-bundle-linux-x86_64-20130717/sdk/build-tools/19.1.0
AAPT=$TOOLS/aapt
PMLIST=adb_shell_pm_list_packages_-f.txt
TEMP=$(echo $(adb shell mktemp -d -p /data/local/tmp) | sed 's/\r//')
mkdir -p packages
[ -f $PMLIST ] || eval $(echo $(basename $PMLIST) | tr '_' ' ') > $PMLIST
while read line; do
package=${line##*:}
apk=${package%%=*}
name=${package#*=}
copy=packages$apk
mkdir -p $(dirname $copy)
if [ ! -s $copy ]; then # copy it because `adb pull` doesn't see /mnt/expand/
adb shell cp -f $apk $TEMP/copy.apk
adb pull $TEMP/copy.apk $copy
fi
label=$($AAPT dump badging $copy || echo ERROR in $copy >&2 | \
sed -n 's/^application-label:\(.\)\(.*\)\1$/\2/p')
echo $name:$label
done < <(sed 's/\r//' $PMLIST)
adb shell rm -rf $TEMP
So I extremely grateful to jcomeau_ictx for providing the info on how to extract application-label info from apk and the idea to pull apk from phone directly!
However I had to make several alteration to script it self:
while read line; do done are breaking as a result of commands within while loop interacting with stdin/stdout and as a result while loop runs only once and then stops, as it is discussed in While loop stops reading after the first line in Bash - the comment from cmo I used solution provided and switched while loop to use unused file descriptor number 9.
All that the script really need is a package name and adb shell pm list packages -f is really excessive so I changed it to expect a file with packages list only and provided example on how one can get one from adb.
jcomeau_ictx script variant do not take in to account that some packages may have multiple apk associated with them which breaks the script.
And the least and last, I made every variable to start with underscore, it's just something that makes it easier to read script.
So here another variant of the same script:
#!/bin/bash
_TOOLS=/opt/android-sdk-update-manager/build-tools/29.0.3
_AAPT=${_TOOLS}/aapt
#adb shell pm list packages --user 0 | sed -e 's|^package:||' | sort >./packages_list.txt
_PMLIST=packages_list.txt
rm ./packages_list_with_names.txt
_TEMP=$(echo $(adb shell mktemp -d -p /data/local/tmp) | sed 's/\r//')
mkdir -p packages
[ -f ${_PMLIST} ] || eval $(echo $(basename ${_PMLIST}) | tr '_' ' ') > ${_PMLIST}
while read -u 9 _line; do
_package=${_line##*:}
_apkpath=$(adb shell pm path ${_package} | sed -e 's|^package:||' | head -n 1)
_apkfilename=$(basename "${_apkpath}")
adb shell cp -f ${_apkpath} ${_TEMP}/copy.apk
adb pull ${_TEMP}/copy.apk ./packages
_name=$(${_AAPT} dump badging ./packages/copy.apk | sed -n 's|^application-label:\(.\)\(.*\)\1$|\2|p' )
#'
echo "${_package} - ${_name}" >>./packages_list_with_names.txt
done 9< ${_PMLIST}
adb shell rm -rf $TEMP

linux shell - can't compare strings with: adb shell getprop ro.product.brand

This is really odd...
I can't get this test to result in true in my linux shell and I can't figure out why.
#!/bin/bash
a=$(adb shell getprop ro.product.brand)
adb shell getprop ro.product.brand
if [ "$a" == "Huawei" ]; then
echo "Success"
else
echo "Failed"
fi
The script just outputs:
Huawei
Failed
Whereas this script:
b=$(whoami)
whoami
if [ "$b" == "amo" ]; then
echo "Success"
else
echo "Failed"
fi
...outputs:
amo
Success
Can anyone help me understand that?
I already tried cutting away spaces or line breaks in $a by piping to cut or sed but I get the same result...
I suggest this as a way to remove leading/trailing whitespace :
# Trims $1
# If $2 supplied, assigns result to variable named $2
# If $2 not present, echoes the value to stdout
trim()
{
if
[[ $1 =~ ^[[:blank:]]*(.*[^[:blank:]])[[:blank:]]*$ ]]
then
local result="${BASH_REMATCH[1]}"
else
local result="$1"
fi
if
(( $# > 1 ))
then
printf -v "$2" %s "$result"
else
printf %s "$result"
fi
}
This function uses no external program, so has low overhead.
Maybe a quick explanation of the regular expression...
^[[:blank:]]*(.*[^[:blank:]])[[:blank:]]*$
It matches all leading and trailing whitespace (no surprise there)
In the middle, it matches any string of characters that ends with a non-blank and saves that as a sub-expression for access with BASH_REMATCH
If there were no "non-blank" character specified to end the middle portion, the greedy .* would eat everything up until the end of the string, including trailing blanks.
The .* is, on the other hand, certain to begin with a non-blank, because the greedy initial [[:blank:]]* will only stop when encountering a non-blank.
Depending on your need, you may also use [[:space:]] instead of [[:blank:]] (difference explained here : https://en.wikipedia.org/wiki/Regular_expression#Character_classes). Basically, [[:blank:]] matches tabs and spaces, and [[:space:]] also matches newlines, carriage returns, and a few more.

How to get Signature hash code of a phone app via adb on pc?

For example, in an android program, I can do it like this:
android.content.pm.Signature[] sigs = pkm.getPackageInfo(
"com.test", PackageManager.GET_SIGNATURES).signatures;
But, how can I do it via adb on PC?
You can do
service call package 2 s16 "com.test" i32 64
and parse the resulting Parcel dump
Alex has a great answer.
WARNING: Ugly code ahead
I was able to get the signature in adb shell as root with the following code:
package=com.test; b=false; while read line; do case $line in *\<package*${package}*) b=true ;; *\<cert*) if $b; then echo $line | sed -e 's|.*key="||' -e 's|".*||'; b=false; fi esac; done < /data/system/packages.xml
indented:
package=com.test
b=false
while read line; do
case $line in
*\<package*${package}*)
b=true ;;
*\<cert*)
if $b; then
echo $line | sed -e 's|.*key="||' -e 's|".*||'
b=false
fi
esac
done < /data/system/packages.xml

Shell script search & replace in text file

I have to edit text file in android shell.
so I type this shell script.
but my Galaxy Nexus does not have Sed, Awk neither.
shell#android:/ $ sed -e "s/old_pattern/new_pattern/g" file_name > modify_file
/system/bin/sh: sed: not found
it doesn't worked.
how can i modify old_pattern to new_pattern in text file.
is it possible in Shell Script?
Edited Shell Script
#!/system/bin/sh
ARGS=4
BAD=65
if [ $# -ne "$ARGS" ]
then
echo "Usage: `basename $0` TARGET_FILE,OLD_PATTERN,NEW_PATTERN,MODIFY_FILE"
exit $BAD
fi
old_pattern=$2
new_pattern=$3
modify_file=$4
if [ -f "$1" ]
then
target_file=$1
else
echo "\"$3\" Does not exist."
exit $BAD
fi
exit 0
Solution :
shell#android:/ $ while read STRING
>do
>echo "${STRING//old_pattern/new_pattern}" >> modify_file_name
>done < target_file_name
shell#android:/ $
It is possible with pure bash, but it will be very slooow on big files.
while read STRING
do
echo "${STRING//old_pattern/new_pattern}" >> modify_file
done < file_name
ps. Oh, I just mentioned that your shell isn't bash. Seems like it is just sh. That won't work with sh.

adb push/pull with progress bar

It is really annoying if you adb push/pull large files to the device that there's no way to now how far along it is. Is it possible to run adb push or adb pull and get a progress bar using the 'bar' utility?
The main issue here is I think that adb expects two file names, if the input file could be replaced by stdin you could pipe through the 'bar' utility and get a progress bar. So far I haven't succeeded in doing so, but I'm not really a shell guru which is why I'm asking here :)
Note that I'm on Linux using bash.
It looks like the latest adb has progress support.
Android Debug Bridge version 1.0.32
device commands:
adb push [-p] <local> <remote>
- copy file/dir to device
('-p' to display the transfer progress)
However, the answers above also work for 'adb install' which do not have a progress option. I modified the first answer's script to work this way:
Create "adb-install.sh" somewhere in your PATH and run "adb-install.sh " instead of "adb install -f "
#!/bin/bash
# adb install with progressbar displayed
# usage: <adb-install.sh> <file.apk>
# original code from: http://stackoverflow.com/questions/6595374/adb-push-pull-with-progress-bar
function usage()
{
echo "$0 <apk to install>"
exit 1
}
function progressbar()
{
bar="================================================================================"
barlength=${#bar}
n=$(($1*barlength/100))
printf "\r[%-${barlength}s] %d%%" "${bar:0:n}" "$1"
# echo -ne "\b$1"
}
export -f progressbar
[[ $# < 1 ]] && usage
SRC=$1
[ ! -f $SRC ] && { \
echo "source file not found"; \
exit 2; \
}
which adb >/dev/null 2>&1 || { \
echo "adb doesn't exist in your path"; \
exit 3; \
}
SIZE=$(ls -l $SRC | awk '{print $5}')
export ADB_TRACE=all
adb install -r $SRC 2>&1 \
| sed -n '/DATA/p' \
| awk -v T=$SIZE 'BEGIN{FS="[=:]"}{t+=$7;system("progressbar " sprintf("%d\n", t/T*100))}'
export ADB_TRACE=
echo
echo 'press any key'
read n
Currently I have this little piece of bash:
function adb_push {
# NOTE: 65544 is the max size adb seems to transfer in one go
TOTALSIZE=$(ls -Rl "$1" | awk '{ sum += sprintf("%.0f\n", ($5 / 65544)+0.5) } END { print sum }')
exp=$(($TOTALSIZE * 7)) # 7 bytes for every line we print - not really accurate if there's a lot of small files :(
# start bar in the background
ADB_TRACE=adb adb push "$1" "$2" 2>&1 | unbuffer -p awk '/DATA/ { split($3,a,"="); print a[2] }' | unbuffer -p cut -d":" -s -f1 | unbuffer -p bar -of /dev/null -s $exp
echo # Add a newline after the progressbar.
}
It works somewhat, it shows a progress bar going from 0 to 100 which is nice. However, it won't be correct if you do a lot of small files, and worse, the bytes/s and total bytes shown by 'bar' aren't correct.
I challenge you to improve on my script; it shouldn't be hard! ;)
Here is my solution, it will show a simple progressbar and current numeric progress
[==================================================] 100%
Usage
./progress_adb.sh source destination
progress_adb.sh
#!/bin/bash
function usage()
{
echo "$0 source destination"
exit 1
}
function progressbar()
{
bar="=================================================="
barlength=${#bar}
n=$(($1*barlength/100))
printf "\r[%-${barlength}s] %d%%" "${bar:0:n}" "$1"
# echo -ne "\b$1"
}
export -f progressbar
[[ $# < 2 ]] && usage
SRC=$1
DST=$2
[ ! -f $SRC ] && { \
echo "source file not found"; \
exit 2; \
}
which adb >/dev/null 2>&1 || { \
echo "adb doesn't exist in your path"; \
exit 3; \
}
SIZE=$(ls -l $SRC | awk '{print $5}')
ADB_TRACE=adb adb push $SRC $DST 2>&1 \
| sed -n '/DATA/p' \
| awk -v T=$SIZE 'BEGIN{FS="[=:]"}{t+=$7;system("progressbar " sprintf("%d\n", t/T*100))}'
echo
Testing on Ubuntu 14.04
$ bash --version
GNU bash, version 4.3.11(1)-release (x86_64-pc-linux-gnu)
TODO
directory support
progressbar size change when screen size change
Well I can give you an Idea:
ADB_TRACE=adb adb push <source> <destination>
returns logs for any command, so for example the copy command, which looks like:
writex: fd=3 len=65544: 4441544100000100000000021efd DATA....#....b..
here you can get the total bytes length before, with ls -a, then parse the output of adb with grep or awk, increment an interneral counter and send the current progress to the bar utility.
When you succeeded, please post the script here.

Categories

Resources