build/envsetup.sh 简介
2018-03-01 14:52
423 查看
build/envsetup.sh
命令————envsetup.sh中的函数简介
source build/envsetup.sh 执行流程
build/envsetup.sh 常用函数介绍
lunch流程
_lunch函数
gettop
hmm
mm
mmm
godir
sgrep
看了好多篇关于build/envsetup.sh 的介绍,记下的总结
envsetup.sh.
常用的命令
Tips: Android源码非常庞大,直接采用grep来搜索代码,不仅方法笨拙、浪费时间,而且搜索出很多无意义的混淆结果。根据具体需求,来选择合适的代码搜索指令,能节省代码搜索时间,提高搜索结果的精准度,方便定位目标代码。
godir [filename] 第一次执行速度较慢,之后运作效率比find命令高(具体见后面解析)
其他指令
make clean:执行清理操作,等价于 rm -rf out/
make update-api:更新API,在framework API改动后需执行该指令,Api记录在目录frameworks/base/api
最最后看看addcompletions干了啥
如果BASH的版本为空或者小于3都直接返回,否则打印android/sdk/bash_completion/目录下的以.bash结尾的所有文件,执行.bash文件,实现Linux终端下adb命令的补全
至此, source build/envsetup.sh的过程就分析完了。
Tips:set_stuff_for_environment 里面的set_java_home函数,可以根据实际情况修改java路径等,这样可以避免编译不同的android版本还需手动切换java版本
首先定义了lunch函数
然后定义了_lunch函数
使用complete命令
++complete -F _lunch lunch++ 是上面代码中最关键的一行。
当bash在遇到lunch这个词的时候,会调用_lunch函数。
该函数会传入三个参数:要补全的命令名、当前的光标所在的词、当前光标所在的词的前一个词。
补全的结果需要存储到COMPREPLY变量中,以待bash获取。
-n 变量是否存在
-a 逻辑与
-f 文件是否存在
PWD 打印当前目录
这个函数主要是获取Android源码的根目录,根据根目录下的build/core/envsetup.mk文件来判断的。
注意:调用这个函数的时候有个要求:就是你必须在源码根目录的子目录中,如果你处在根目录的上级目录则调用失败,因为这个函数是通过不停的调用cd ..命令,然后通过文件build/core/envsetup.mk来判断源码根目录的。
帮助函数,cat $T/build/envsetup.sh | sed -n “/^[ \t]function /s/function ([a-z_]).*/\1/p” | sort | uniq 这句脚本主要是获取envsetup.sh里面的以function开头的函数,函数名都是字母,并将函数名打印出来。
sed -n “/^[ \t]*function /p” 是打印出以function 开头的行
s/function ([a-z_])./\1 这部分是将函数名提取出来
sort 排序
uniq 去重
如果当前处在源码根目录下,且存在Makefile文件,直接执行make $@命令。
如果不是在源码根目录下:循环调用cd .. 调用findmakefile函数查找Android.mk文件,直到根目录,将Android.mk文件的绝对路径返回给M.
如找到了:M=/home/admin/android/frameworks/base/Android.mk,调用: local M=
最后执行:ONE_SHOT_MAKEFILE=frameworks/base/android.mk make -C /home/admin/android all_modules
相当于make -C /home/admin/android all_modules ONE_SHOT_MAKEFILE=frameworks/base/android.mk
接下来会调用到:源码根目录下的Makefile中,我们发现内容是include build/core/main.mk,即走到了build/core/main.mk文件中。后面就设计到Makefile的问题,我们后面会分析。现在只需要知道mm命令是怎么调用makefile里面去就行
首先T=$(gettop)获取源码根目录,
根据mmm后面的参数获取以空格隔开,以-开头的字符串,如:mmm -B frameworks/base 则DASH_ARGS = -B
根据mmm后面参数获取以空格隔开,不以-开头的字符串。如:DIRS=frameworks/base/
去掉DIR结尾的/,DIR=frameworks/base
跳到源码根目录,pwd -P打印出来,获取到字符串长度如:/home/admin/androids TO_CHOP就是20
获取当前目录字符串,去掉前面21个字符,如:当前目录为/home/admin/androids,则MFILE=”“
这里进行判断当前目录是否就是源码目录,如果是的话,MFILE为空,所以MFILe=frameworks/base/Android.mk
否则:MFILE=$MFILE/frameworks/base/Android.mk
总之:就是把当前目录的前面源码根目录去了,然后加上后面mmm -B **参数部分相对的目录,最后加上Android.mk就是,最后Android.mk文件的相对路径。
ONE_SHOT_MAKEFILE=”MAKEFILE” make -C TTDASH_ARGS all_modules $ARGS
相当于:make -C /home/admin/android -B all_modules ONE_SHOT_MAKEFILE=frameworks/base/Android.mk
godir 是在编译路径下搜索匹配模式的目录,然后跳转到此目录,同时可以用来快速查找文件的路径
如像查找frameworks/base/core/res/res/values在那些地方被overlay 了直接godir frameworks/base/core/res/res/values/ 查找包含这个路径的所有文件夹,及所有可能被覆盖的地方
这里为什么没有把out目录去了表示无法理解
其他代码搜索原理类似就不一一列举
命令————envsetup.sh中的函数简介
source build/envsetup.sh 执行流程
build/envsetup.sh 常用函数介绍
lunch流程
_lunch函数
gettop
hmm
mm
mmm
godir
sgrep
看了好多篇关于build/envsetup.sh 的介绍,记下的总结
build/envsetup.sh
每次开始编译开始的第一个命令便是source build/envsetup.sh,其中source命令就是用于运行shell脚本命令,功能等价于”.”,因此该命令也等价于. build/envsetup.sh。在文件envsetup.sh声明了当前会话终端可用的命令,这里需要注意的是当前会话终端,也就意味着每次新打开一个终端都必须再一次执行这些指令。build/envsetup.sh文件存在的意义就是,设置一些环境变量和shell函数为后续的编译工作做准备。 接下来我们分析下envsetup.sh.
命令————envsetup.sh中的函数简介
导入envsetup.sh系统会都出一些命令,先看下命令的作用常用的命令
编译指令 | 解释 |
---|---|
mm | 编译当前路径下所有模块,但不包含依赖 |
mmm [module_path] | 编译指定路径下所有模块,但不包含依赖 |
mma | 编译当前路径下所有模块,且包含依赖 |
mmma [module_path] | 编译指定路径下所有模块,且包含依赖 |
make [module_name] | 无参数,则表示编译整个Android代码 |
cgrep | 当前目录下所有C/C++文件执行搜索操作 |
jgrep | 当前目录下所有Java文件执行搜索操作 |
ggrep | 当前目录下所有Gradle文件执行搜索操作 |
mangrep [keyword] | 当前目录下所有AndroidManifest.xml文件执行搜索操作 |
mgrep [keyword] | 当前目录下所有Android.mk文件执行搜索操作 |
sepgrep [keyword] | 所有sepolicy文件执行搜索操作 |
resgrep [keyword] | 当前目录下所有本地res/*.xml文件执行搜索操作 |
sgrep [keyword] | 当前目录下基于(c |
croot | 切换至Android根目录 |
cproj | 切换至工程的根目录 |
godir [filename] | 跳转到包含某个文件的目录 |
hmm | 查询所有的指令help信息 |
godir [filename] 第一次执行速度较慢,之后运作效率比find命令高(具体见后面解析)
其他指令
make clean:执行清理操作,等价于 rm -rf out/
make update-api:更新API,在framework API改动后需执行该指令,Api记录在目录frameworks/base/api
source build/envsetup.sh 执行流程
envsetup.sh 定义了很多函数,除此之外还执行了其它操作,以下是除去函数部分的代码::VARIANT_CHOICES=(user userdebug eng)# 提前定义3种编译模式,供后面使用 # Clear this variable. It will be built up again when the vendorsetup.sh # files are included at the end of this file. #LUNCH_MENU_CHOICES是供用户选择的prodcut列表, #每次source build/envsetup.sh时需重置变量LUNCH_MENU_CHOICES #不然后续的include vendor/cm/vendorsetup.sh时会继续添加产品至变量LUNCH_MENU_CHOICES里, #导致出现很多重复产品 unset LUNCH_MENU_CHOICES #处理逻辑就是先从LUNCH_MENU_CHOICES中循环查找,看存不存在要添加的板型,如果存在就直接返回,如果不存在就添加到LUNCH_MENU_CHOICES中 function add_lunch_combo() { local new_combo=$1 local c for c in ${LUNCH_MENU_CHOICES[@]} ; do if [ "$new_combo" = "$c" ] ; then return fi done LUNCH_MENU_CHOICES=(${LUNCH_MENU_CHOICES[@]} $new_combo) } #默认会加载如下6个板型选项 # add the default one here add_lunch_combo aosp_arm-eng add_lunch_combo aosp_arm64-eng add_lunch_combo aosp_mips-eng add_lunch_combo aosp_mips64-eng add_lunch_combo aosp_x86-eng add_lunch_combo aosp_x86_64-eng # 这行代码前定义了lunch和_lunch函数,这行代码的意思是通过_lunch函数实现lunch命令的自动补全功能 complete -F _lunch lunch #shell检查和警告,这里只支持bash,如果是其他的shell会发出这个WARNING if [ "x$SHELL" != "x/bin/bash" ]; then case `ps -o command -p $$` in *bash*) ;; *) echo "WARNING: Only bash is supported, use of other shell would lead to erroneous results" ;; esac fi # Execute the contents of any vendorsetup.sh files we can find. #source vendor和device下能找到的所有vendorsetup.sh for f in `test -d device && find -L device -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort` \ `test -d vendor && find -L vendor -maxdepth 4 -name 'vendorsetup.sh' 2> /dev/null | sort` do echo "including $f" . $f done unset f addcompletions
最最后看看addcompletions干了啥
function addcompletions() { local T dir f # Keep us from trying to run in something that isn't bash. if [ -z "${BASH_VERSION}" ]; then return fi # Keep us from trying to run in bash that's too old. if [ ${BASH_VERSINFO[0]} -lt 3 ]; then return fi dir="sdk/bash_completion" if [ -d ${dir} ]; then for f in `/bin/ls ${dir}/[a-z]*.bash 2> /dev/null`; do echo "including $f" . $f done fi }
如果BASH的版本为空或者小于3都直接返回,否则打印android/sdk/bash_completion/目录下的以.bash结尾的所有文件,执行.bash文件,实现Linux终端下adb命令的补全
至此, source build/envsetup.sh的过程就分析完了。
build/envsetup.sh 常用函数介绍
lunch流程
在source流程之后,紧接着就是执行lunch操作,lunch操作执行的其实就是build/envsetup.sh脚本中的lunch函数,直接看代码:function lunch() { local answer #如果lunch命令后跟有参数,则直接赋给answer变量; #如果lunch命令后没有参数,则调用函数print_lunch_menu打印出板型列表供用户选择,并将用户的选择存储在answer变量中。 if [ "$1" ] ; then answer=$1 else print_lunch_menu #函数的作用就是打印数组LUNCH_MENU_CHOICES的内容 echo -n "Which would you like? [aosp_arm-eng] " read answer fi local selection= #如果answer为空,则selection默认赋值为aosp_arm-eng; #如果answer是纯数字,则将answer作为数组下标从LUNCH_MENU_CHOICES数组中取出板型名称; #如果anwser是字符串,并且字符串使用”-”连接,而且”-”连接的前后两个子串中都没有”-”,则认为是板型名称字符串,直接赋给selection。 if [ -z "$answer" ] then selection=aosp_arm-eng elif (echo -n $answer | grep -q -e "^[0-9][0-9]*$") then if [ $answer -le ${#LUNCH_MENU_CHOICES[@]} ] then selection=${LUNCH_MENU_CHOICES[$(($answer-1))]} fi elif (echo -n $answer | grep -q -e "^[^\-][^\-]*-[^\-][^\-]*$") then selection=$answer fi #如果selection仍然为空,则直接报错并退出 if [ -z "$selection" ] then echo echo "Invalid lunch combo: $answer" return 1 fi export TARGET_BUILD_APPS= #从selection中取出“-”前面的字符串到product, local product=$(echo -n $selection | sed -e "s/-.*$//") #检查product的合法性,涉及到make 不展开 check_product $product if [ $? -ne 0 ] then echo echo "** Don't have a product spec for: '$product'" echo "** Do you have the right repo manifest?" product= fi #再从selection中取出“-”后面的字符串到variant,然后调用函数check_variant判断variant是否符合要求。check_variant函数很简单,主要就是用到前文source流程中初始化为"user userdebug eng"的VARIANT_CHOICES数组,判断variant是否是数组成员之一,是则返回0,不是则返回1。 local variant=$(echo -n $selection | sed -e "s/^[^\-]*-//") check_variant $variant if [ $? -ne 0 ] then echo echo "** Invalid variant: '$variant'" echo "** Must be one of ${VARIANT_CHOICES[@]}" variant= fi if [ -z "$product" -o -z "$variant" ] then echo return 1 fi #导出以下准备好的宏变量供整个shell环境使用 export TARGET_PRODUCT=$product export TARGET_BUILD_VARIANT=$variant export TARGET_BUILD_TYPE=release echo #设置PROMPT_COMMAND,ANDROID_BUILD_PATHS,JAVA_HOME和BUILD_ENV_SEQUENCE_NUMBER等等环境变量 set_stuff_for_environment #打印最终准备好的环境变量 printconfig }
Tips:set_stuff_for_environment 里面的set_java_home函数,可以根据实际情况修改java路径等,这样可以避免编译不同的android版本还需手动切换java版本
_lunch函数
实现lunch命令的补全的步骤:首先定义了lunch函数
然后定义了_lunch函数
使用complete命令
# Tab completion for lunch. function _lunch() { local cur prev opts COMPREPLY=() cur="${COMP_WORDS[COMP_CWORD]}" prev="${COMP_WORDS[COMP_CWORD-1]}" COMPREPLY=( $(compgen -W "${LUNCH_MENU_CHOICES[*]}" -- ${cur}) ) return 0 }
++complete -F _lunch lunch++ 是上面代码中最关键的一行。
当bash在遇到lunch这个词的时候,会调用_lunch函数。
该函数会传入三个参数:要补全的命令名、当前的光标所在的词、当前光标所在的词的前一个词。
补全的结果需要存储到COMPREPLY变量中,以待bash获取。
gettop
function gettop { local TOPFILE=build/core/envsetup.mk if [ -n "$TOP" -a -f "$TOP/$TOPFILE" ] ; then # The following circumlocution ensures we remove symlinks from TOP. (cd $TOP; PWD= /bin/pwd) else if [ -f $TOPFILE ] ; then # The following circumlocution (repeated below as well) ensures # that we record the true directory name and not one that is # faked up with symlink names. PWD= /bin/pwd else local HERE=$PWD T= while [ \( ! \( -f $TOPFILE \) \) -a \( $PWD != "/" \) ]; do \cd .. T=`PWD= /bin/pwd -P` done \cd $HERE if [ -f "$T/$TOPFILE" ]; then echo $T fi fi fi }
-n 变量是否存在
-a 逻辑与
-f 文件是否存在
PWD 打印当前目录
这个函数主要是获取Android源码的根目录,根据根目录下的build/core/envsetup.mk文件来判断的。
注意:调用这个函数的时候有个要求:就是你必须在源码根目录的子目录中,如果你处在根目录的上级目录则调用失败,因为这个函数是通过不停的调用cd ..命令,然后通过文件build/core/envsetup.mk来判断源码根目录的。
hmm
function hmm() { cat <<EOF Invoke ". build/envsetup.sh" from your shell to add the following functions to your environment: - lunch: lunch <product_name>-<build_variant> - tapas: tapas [<App1> <App2> ...] [arm|x86|mips|armv5|arm64|x86_64|mips64] [eng|userdebug|user] - croot: Changes directory to the top of the tree. - m: Makes from the top of the tree. - mm: Builds all of the modules in the current directory, but not their dependencies. - mmm: Builds all of the modules in the supplied directories, but not their dependencies. To limit the modules being built use the syntax: mmm dir/:target1,target2. - mma: Builds all of the modules in the current directory, and their dependencies. - mmma: Builds all of the modules in the supplied directories, and their dependencies. - cgrep: Greps on all local C/C++ files. - ggrep: Greps on all local Gradle files. - jgrep: Greps on all local Java files. - resgrep: Greps on all local res/*.xml files. - mangrep: Greps on all local AndroidManifest.xml files. - sepgrep: Greps on all local sepolicy files. - sgrep: Greps on all local source files. - godir: Go to the directory containing a file. Environemnt options: - SANITIZE_HOST: Set to 'true' to use ASAN for all host modules. Note that ASAN_OPTIONS=detect_leaks=0 will be set by default until the build is leak-check clean. Look at the source to view more functions. The complete list is: EOF T=$(gettop) local A A="" for i in `cat $T/build/envsetup.sh | sed -n "/^[ \t]*function /s/function \([a-z_]*\).*/\1/p" | sort | uniq`; do A="$A $i" done echo $A }
帮助函数,cat $T/build/envsetup.sh | sed -n “/^[ \t]function /s/function ([a-z_]).*/\1/p” | sort | uniq 这句脚本主要是获取envsetup.sh里面的以function开头的函数,函数名都是字母,并将函数名打印出来。
sed -n “/^[ \t]*function /p” 是打印出以function 开头的行
s/function ([a-z_])./\1 这部分是将函数名提取出来
sort 排序
uniq 去重
mm
function mm() { local T=$(gettop) local DRV=$(getdriver $T) # If we're sitting in the root of the build tree, just do a # normal make. if [ -f build/core/envsetup.mk -a -f Makefile ]; then $DRV make $@ else # Find the closest Android.mk file. local M=$(findmakefile) local MODULES= local GET_INSTALL_PATH= local ARGS= # Remove the path to top as the makefilepath needs to be relative local M=`echo $M|sed 's:'$T'/::'` if [ ! "$T" ]; then echo "Couldn't locate the top of the tree. Try setting TOP." return 1 elif [ ! "$M" ]; then echo "Couldn't locate a makefile from the current directory." return 1 else for ARG in $@; do case $ARG in GET-INSTALL-PATH) GET_INSTALL_PATH=$ARG;; esac done if [ -n "$GET_INSTALL_PATH" ]; then MODULES= ARGS=GET-INSTALL-PATH else MODULES=all_modules ARGS=$@ fi ONE_SHOT_MAKEFILE=$M $DRV make -C $T -f build/core/main.mk $MODULES $ARGS fi fi }
如果当前处在源码根目录下,且存在Makefile文件,直接执行make $@命令。
如果不是在源码根目录下:循环调用cd .. 调用findmakefile函数查找Android.mk文件,直到根目录,将Android.mk文件的绝对路径返回给M.
如找到了:M=/home/admin/android/frameworks/base/Android.mk,调用: local M=
echo $M|sed 's}'$T'/}}'这句就是将源码根目录/home/admin/android/去掉,取得相对目录后,M=frameworks/base/Android.mk
最后执行:ONE_SHOT_MAKEFILE=frameworks/base/android.mk make -C /home/admin/android all_modules
相当于make -C /home/admin/android all_modules ONE_SHOT_MAKEFILE=frameworks/base/android.mk
接下来会调用到:源码根目录下的Makefile中,我们发现内容是include build/core/main.mk,即走到了build/core/main.mk文件中。后面就设计到Makefile的问题,我们后面会分析。现在只需要知道mm命令是怎么调用makefile里面去就行
mmm
mmm 命令就是从指定目录下开始编译所有模块function mmm() { local T=$(gettop) local DRV=$(getdriver $T) if [ "$T" ]; then local MAKEFILE= local MODULES= local ARGS= local DIR TO_CHOP local GET_INSTALL_PATH= local DASH_ARGS=$(echo "$@" | awk -v RS=" " -v ORS=" " '/^-.*$/') local DIRS=$(echo "$@" | awk -v RS=" " -v ORS=" " '/^[^-].*$/') for DIR in $DIRS ; do MODULES=`echo $DIR | sed -n -e 's/.*:\(.*$\)/\1/p' | sed 's/,/ /'` if [ "$MODULES" = "" ]; then MODULES=all_modules fi DIR=`echo $DIR | sed -e 's/:.*//' -e 's:/$::'` if [ -f $DIR/Android.mk ]; then local TO_CHOP=`(\cd -P -- $T && pwd -P) | wc -c | tr -d ' '` local TO_CHOP=`expr $TO_CHOP + 1` local START=`PWD= /bin/pwd` local MFILE=`echo $START | cut -c${TO_CHOP}-` if [ "$MFILE" = "" ] ; then MFILE=$DIR/Android.mk else MFILE=$MFILE/$DIR/Android.mk fi MAKEFILE="$MAKEFILE $MFILE" else case $DIR in showcommands | snod | dist | incrementaljavac | *=*) ARGS="$ARGS $DIR";; GET-INSTALL-PATH) GET_INSTALL_PATH=$DIR;; *) echo "No Android.mk in $DIR."; return 1;; esac fi done if [ -n "$GET_INSTALL_PATH" ]; then ARGS=$GET_INSTALL_PATH MODULES= fi ONE_SHOT_MAKEFILE="$MAKEFILE" $DRV make -C $T -f build/core/main.mk $DASH_ARGS $MODULES $ARGS else echo "Couldn't locate the top of the tree. Try setting TOP." return 1 fi }
首先T=$(gettop)获取源码根目录,
local DASH_ARGS=$(echo "$@" | awk -v RS=" " -v ORS=" " '/^-.*$/')
根据mmm后面的参数获取以空格隔开,以-开头的字符串,如:mmm -B frameworks/base 则DASH_ARGS = -B
local DIRS=$(echo "$@" | awk -v RS=" " -v ORS=" " '/^[^-].*$/')
根据mmm后面参数获取以空格隔开,不以-开头的字符串。如:DIRS=frameworks/base/
DIR=`echo $DIR | sed -e 's:/$::'`
去掉DIR结尾的/,DIR=frameworks/base
if [ -f $DIR/Android.mk ] ;then TO_CHOP=`(cd -P -- $T && pwd -P) | wc -c | tr -d ' '`
跳到源码根目录,pwd -P打印出来,获取到字符串长度如:/home/admin/androids TO_CHOP就是20
TO_CHOP=`expr $TO_CHOP + 1` START=`PWD= /bin/pwd` MFILE=`echo $START | cut -c${TO_CHOP}-`
获取当前目录字符串,去掉前面21个字符,如:当前目录为/home/admin/androids,则MFILE=”“
if [ "$MFILE" = "" ] ; then MFILE=$DIR/Android.mk else MFILE=$MFILE/frameworks/base/Android.mk fi
这里进行判断当前目录是否就是源码目录,如果是的话,MFILE为空,所以MFILe=frameworks/base/Android.mk
否则:MFILE=$MFILE/frameworks/base/Android.mk
总之:就是把当前目录的前面源码根目录去了,然后加上后面mmm -B **参数部分相对的目录,最后加上Android.mk就是,最后Android.mk文件的相对路径。
ONE_SHOT_MAKEFILE=”MAKEFILE” make -C TTDASH_ARGS all_modules $ARGS
相当于:make -C /home/admin/android -B all_modules ONE_SHOT_MAKEFILE=frameworks/base/Android.mk
godir
function godir () { #如果没有带参数直接提示错误返回 if [[ -z "$1" ]]; then echo "Usage: godir <regex>" return fi T=$(gettop) #如果OUT_DIR 不等于空创建OUT_DIR这个目录,设置FILELIST文件路径 if [ ! "$OUT_DIR" = "" ]; then mkdir -p $OUT_DIR FILELIST=$OUT_DIR/filelist else FILELIST=$T/filelist fi #判断filelist是否存在,不存在新建 if [[ ! -f $FILELIST ]]; then echo -n "Creating index..." # 使用find命令从编译的根目录下查找文件"-type f"(目录out和.repo除外),并将结果输出到$FILELIST文件中 # out目录和.repo目录的排除选项分别为: # - "-wholename ./out -prune" # - "-wholename ./.repo -prune" # 关于find的"-wholename pattern"选项,其行为跟"-path pattern"基本一样,具体可以查看find的帮助信息 # 因此filelist文件保存了除out和.repo目录外其余目录的完整文件名 (\cd $T; find . -wholename ./out -prune -o -wholename ./.repo -prune -o -type f > $FILELIST) echo " Done" echo "" fi local lines # 根据传入godir的参数,在filelist中搜索,并用sed处理后将结果存放在lines中 # 操作"sed -e 's/\/[^/]*$//'"仅保留完整文件名的路径部分 lines=($(\grep "$1" $FILELIST | sed -e 's/\/[^/]*$//' | sort | uniq)) # 检查lines中的结果,即filelist通过grep和sed操作后,是否还有匹配的目录 if [[ ${#lines[@]} = 0 ]]; then echo "Not found" return fi local pathname local choice # 如果lines的结果多于1行,则对各行进行编号并输出 if [[ ${#lines[@]} > 1 ]]; then while [[ -z "$pathname" ]]; do # 从1开始编号 local index=1 local line for line in ${lines[@]}; do # 对每行以类似以下的格式进行输出: printf "%6s %s\n" "[$index]" $line # 序号自增 index=$(($index + 1)) done echo echo -n "Select one: " unset choice # 读取输入序号 read choice if [[ $choice -gt ${#lines[@]} || $choice -lt 1 ]]; then echo "Invalid choice" continue fi # 取得输入序号对应的目录 pathname=${lines[$(($choice-1))]} done else # 如果符合匹配的路径只有一条,则直接将匹配的路径存放到pathname中 pathname=${lines[0]} fi 跳转到 \cd $T/$pathname }
godir 是在编译路径下搜索匹配模式的目录,然后跳转到此目录,同时可以用来快速查找文件的路径
如像查找frameworks/base/core/res/res/values在那些地方被overlay 了直接godir frameworks/base/core/res/res/values/ 查找包含这个路径的所有文件夹,及所有可能被覆盖的地方
sgrep
case `uname -s` in Darwin) function sgrep() { find -E . -name .repo -prune -o -name .git -prune -o -type f -iregex '.*\.(c|h|cc|cpp|S|java|xml|sh|mk|aidl)' -print0 | xargs -0 grep --color -n "$@" } ;; *) function sgrep() { # 排除 .repo, .git目录 # 并对后缀(c|h|cc|cpp|S|java|xml|sh|mk|aidl|vts)的文件执行grep模式搜索 find . -name .repo -prune -o -name .git -prune -o -type f -iregex '.*\.\(c\|h\|cc\|cpp\|S\|java\|xml\|sh\|mk\|aidl\)' -print0 | xargs -0 grep --color -n "$@" } ;; esac
这里为什么没有把out目录去了表示无法理解
其他代码搜索原理类似就不一一列举
相关文章推荐
- build/envsetup.sh 简介
- build/envsetup.sh 简介2
- build/envsetup.sh 简介
- build/envsetup.sh的简介
- build/envsetup.sh 简介
- build/envsetup.sh 简介
- build/envsetup.sh 简介
- build/envsetup.sh 简介
- 关于Android.mk和build/envsetup.sh的一些小小理解
- build/envsetup.sh
- build/envsetup.sh分析
- Android Donut Makefile分析 (build/envsetup.sh)
- Android build/envsetup.sh分析
- build/envsetup.sh简记
- build/envsetup.sh简记Android系统编译分析
- build/envsetup.sh脚本分析
- build/envsetup.sh中hmm、get_abs_build_var、get_build_var解析
- build/envsetup.sh 学习
- build/envsetup.sh简记Android
- build/envsetup.sh脚本分析