浅析Android设备中grep命令处理流程

时间:2022-12-31 09:25:03

2017-04-18

 

概述

    在TV开发板中,可以在串口中直接使用grep命令。这是因为在/system/bin/下有一个'grep'链接。这个链接指向'/system/bin/toolbox'程序。
浅析Android设备中grep命令处理流程
【图1】
当在串口中键入:
grep um
命令时也就等效于键入
toolbox grep um
 
  toolbox程序是Android系统中携带的工具​之一。其源码位于:
./system/core/toolbox/

浅析Android设备中grep命令处理流程

【图2】

  由上图2可以看到该目录下包含有大多数常用命令的源代码。toolbox程序的意义就是将这些零散的程序的入口进行打包。根据用户在串口中键入的toolbox命令后面的参数不同来选择执行对应的程序。例如,当键入上述的 ‘toolbox grep um’命令时,系统会先将命令的参数通过toolbox的进行解析,最终调用grep.c中的grep_main()函数进行二次解析。

 

toolbox处理流程

./system/core/toolbox/toolbox.c
  该源码文件结构简单。内部仅两个函数:1.int main(int argc, char **argv);2.static int toolbox_main(int argc, char **argv);以及一个封装了各工具集入口函数的结构体数组tools[]。在这个源码中,最重要的就是这个静态结构体数组,其定义如下:
 #define TOOL(name) int name##_main(int, char**);
#include "tools.h"
#undef TOOL static struct
{
const char *name;
int (*func)(int, char**);
} tools[] = {
{ "toolbox", toolbox_main },
#define TOOL(name) { #name, name##_main },
#include "tools.h"
#undef TOOL
{ , },
};
  上述代码中,第1~3行的定义方式在我看来很新奇。但此处就简单把它理解成从tools.h中读取定义的信息,事实上也确实是这样。然后将这些字符串替换成相应的函数声明。tools.h是在本目录下的Android.mk文件中生成的。位于out目录下。
 浅析Android设备中grep命令处理流程
其内容类型如下
浅析Android设备中grep命令处理流程
上述代码中,第1~3行是声明各工具的入口函数。第11~13行是使用这些外部函数。经过这样的声明以后,toolbox程序在运行时这个tools数组的实际值为
 tools[] = {
{ "toolbox", toolbox_main },
{"ls", ls_main},
.
.
.
{"grep", grep_main},
{ , },
};
而tools结构体的第二个参数又是一个函数指针,因此,tools数组中包含的就是toolbox目录下的所有工具的入口函数。估计这也是它会被取名为toolbox的原因吧。
 
  在运行toolbox程序的时候,首先会调用其主函数main()。在这个主函数main()中主要就是取跟在toolbox后面的参数来决定到底是要执行哪一个工具程序。如当键入:toolbox ls。则toolbox.c的执行顺序为:1.main();2.toolbox_main();3.main();4.ls_main()
 

grep

    grep程序的入口函数为:grep_main()
 ./system/core/toolbox/grep/grep.c
在这个文件的首部,定义了多个标志位用于区分不同的参数响应。
浅析Android设备中grep命令处理流程
常用的功能及其执行参数都已标示了出来。
    在grep_main()函数中,首先判断了键入参数的首字符。 __progname[0]等效于argv[0][0]。一般我们使用grep命令时,都是键入grep -n "xx",这时,__progname[0]得到的值就是字符g。看注释貌似是说区分于二进制模式下的什么什么的。对于我们由串口键入命令来执行程序的情况,是统一解析成字符g的,故而不需要理会它的真实用意。
浅析Android设备中grep命令处理流程
 
    然后会从环境变量中读取搜索环境。
浅析Android设备中grep命令处理流程
读取到环境变量后做了什么事,我们姑且不管。不过这个的结果一般都是(null),因此实际上会执行如下操作:
浅析Android设备中grep命令处理流程
    接下来就是去解析命令后面跟的参数了。
浅析Android设备中grep命令处理流程
图【3】
函数getopt_long()的含义可查询百度。
不得不承认,这个函数的功能很强大。它能解析各种花式输入的参数。同时它还具有排序的功能,将花式输入的命令行重新排序成'grep'在前,参数在其中,需要筛选的字符串在末尾的顺序。具体功能验证如下系列图所示,getopt_long()的排序功能验证如下图7所示。
浅析Android设备中grep命令处理流程

浅析Android设备中grep命令处理流程

浅析Android设备中grep命令处理流程

浅析Android设备中grep命令处理流程

浅析Android设备中grep命令处理流程

    总之,经过图3所示的while循环后,能够识别所有的参数。例如,识别-n参数的代码如下图所示。
浅析Android设备中grep命令处理流程
    接下来就是筛减aargv中的参数。
浅析Android设备中grep命令处理流程
其中,optind是getopt_long()函数中的一个变量,它的值是键入的'grep'字符串以及所有的参数的数量。
 
    接下来是去读取需要过滤的字符串。
浅析Android设备中grep命令处理流程
当键入的参数中包含-e  -f 时,needpattern的值就是0,否则为1。
由此处代码可知,grep命令仅能搜索一个参数。add_pattern()函数的实现如下图所示。
浅析Android设备中grep命令处理流程
【图4】
    此函数的代码也算简单。grep命令是在pattern[]数组中保存要过滤的字符串的(pattern是一个二维数组)。而这个数组又被设计成“自动扩容”的形式。上图4所示代码中第230行的条件块就是一个自动扩容的处理流程了。grep_realloc()函数的定义位于
 ./system/core/toolbox/grep/util.c
然后将这个要过滤的字符串添加到pattern[]数组的末尾。至此,整个命令的解析就已经完成了。接下来就要开始执行过滤操作了。
    接下来就是
浅析Android设备中grep命令处理流程
这个grepbehave在grep_main()的首部就已被赋值。对于我们由串口键入命令的情况来说,其值恒为GREP_BASIC。这里,不必理会。
 
    接下来是
浅析Android设备中grep命令处理流程
这一块的作用我也不知道。程序一般会走694行。看695行的函数名fastcomp(),猜它应该是一个快速对比的功能。这个函数的定义位于
 ./system/core/toolbox/grep/fastgrep.c
有兴趣的话可以去详细阅读一下源码。这个函数返回0表示成功,返回-1表示失败。经测试,都是返回-1。此处略过这块代码。
 
    接下来是搜索前的最后的设置。
浅析Android设备中grep命令处理流程
707行的lbflag是行缓冲。浅析Android设备中grep命令处理流程目前并不知道它的具体作用。经测试,由串口键入命令的方式,该值一般为0。此处暂时不予理会。
710行的Hflag,浅析Android设备中grep命令处理流程。该值默认为0。
由713行,当键入的过滤字符串只有一个时,就进行过滤操作,然后退出grep程序。
否则,就执行下面的代码。多个过滤字符串中后面的将会被认为是文件或目录的路径。这样就会被系统理解为在这个目录或文件中执行搜索命令。
浅析Android设备中grep命令处理流程
dirbehave在键入的参数中有'-r'时其值会为DIR_RECURSE。其它情况,则执行else分支。
这里,暂时不讨论指定文件或目录的情况。
 
procfile()函数位于
 ./system/core/toolbox/grep/util.c
浅析Android设备中grep命令处理流程
    这个函数内部定义了几个结构体变量。其中file与str结构体的定义位于
 ./system/core/toolbox/grep/grep.h
浅析Android设备中grep命令处理流程

浅析Android设备中grep命令处理流程

    file结构体结构简单,内部仅保存文件的句柄及这个文件是否是二进制文件的标志。str结构体也简单。其中*dat保存的是当前剩余要过滤的数据。对于在串口中使用grep而言,就是当前获得的文件流中的所有内容。
浅析Android设备中grep命令处理流程
对于只有一个过滤字符串的情况,会执行上图所示代码中的197行代码块。且对于在串口中键入命令的情况,198行的fn得到的值是(standard input)。即标准输入流,而非某个文件流。接着去grep_open(NULL)函数,这个函数位于
 ./system/core/toolbox/grep/file.c
这个函数的结构也简单,
浅析Android设备中grep命令处理流程
这个函数的重点在于第241行处。它会将文件结构体的文件句柄指向标准输入流处。
    接着再回到util.c处继续往下执行,现在就到了从流中过滤数据的时候了。核心代码如下图所示,
浅析Android设备中grep命令处理流程
上面这个for循环语句就是用来过滤关键字并将结果打印在控制台用的。在第226行for循环的条件判断处可以看到两个状态位lflag与qflag。前面的状态位是标志是否只打印文件名,后面的状态位则是标志是否静默搜索(将结果输出到文件或其它什么的)。
 
    上图所示代码中,第228行的if语句的作用就是逐行读取源数据ln.dat。然后跳到第242行。这里调用了procline函数。上面的procfile是处理整个文件流,读取出一行数据后就传到procline中作进一步处理。随后procline在匹配到符合条件的行后,传到printline函数中打印出来。这三个函数均在util.c文件中。具体的实现流程就不再赘述了。
 
grep的详细流程在我看来是很复杂的,没有必要去弄懂这个流程中每一行代码的意义,只需要了解个大概流程就好了,毕竟是抱着扩充知识面而非研究代码的目的去学习的。

浅析Android设备中grep命令处理流程的更多相关文章

  1. 通过ADB命令行卸载或删除你的Android设备中的应用(转载)

    转自:http://mytiankong.com/?p=11755 如果你对你的Android设备在与命令行的交互间有一定的兴趣,那你可能想学习一些使用ADB卸载设备中已安装应用的技巧.为了使这种方法 ...

  2. bat如何创建多级文件夹(在android设备中)

    在android设备中要创建多个或者多级文件夹时,手动去创建费时费力(有点傻),一个bat文件就能很好的实现这个功能. 1.首先创建同级多个文件夹且在该文件夹下生成一个文件 @echo off ech ...

  3. Android开发中adb命令的常用方法

    Android的SDK中提供了很多有用的工具,在开发过程中如果能熟练使用这些工具,会让我们的开发事半功倍.adb是SDK提供的一个常用的命令行工具,全称为Android Debug Bridge,用于 ...

  4. 从Android设备中提取内核和逆向分析

    本文博客链接:http://blog.csdn.net/qq1084283172/article/details/57074695 一.手机设备环境 Model number: Nexus 5 OS ...

  5. 12个 Linux 中 grep 命令的超级用法实例

    12个 Linux 中 grep 命令的超级用法实例 你是否遇到过需要在文件中查找一个特定的字符串或者样式,但是不知道从哪儿开始?那么,就请grep来帮你吧. grep是每个Linux发行版都预装的一 ...

  6. linux中grep命令的使用

    转载:http://blog.csdn.net/universsky/article/details/8866402 linux中grep命令的使用 grep (global search regul ...

  7. 在桌面chrome中调试android设备中的web页面

    准备工作 1, 桌面版chrome 2, Android设备(安装有chrome浏览器) 3, Android-sdk Android-sdk安装及设置 SKD安装 从http://developer ...

  8. 如何获得Android设备名称(ADB命令详细介绍)

    豌豆荚.360手机管家等软件可以获取android设备名称,显示在界面上,如下图: 我们自己如何来获取设备名称 呢?答案如下: 在命令行中输入“adb shell”进入shell之后,再输入“cat ...

  9. shell 中grep命令详解

    用‘grep’搜索文本文件如果您要在几个文本文件中查找一字符串,可以使用‘grep’命令.‘grep’在文本中搜索指定的字符串.举个例子:假设您正在‘/usr/src/linux/Documentat ...

随机推荐

  1. (转)将cocos2dx项目从VS移植到Eclipse

    本文转自:http://www.cnblogs.com/Z-XML/p/3349518.html 引言:我们使用cocos2d-x引擎制作了一款飞行射击游戏,其中创新性地融入了手势识别功能.但是我 们 ...

  2. css压缩(一)

    基于require.js的压缩,至于require.js,网上有比较权威的解说 RequireJS进阶(一) RequireJS进阶(二) RequireJS进阶(三) 目前我所做的项目是把各个模块下 ...

  3. fpu栈溢出

    老大们遇到个问题,有一堆浮点数运算,分开写就对,合一起就溢出. 是因为定义的函数返回float的时候,别的地方声明是void错了,这样的错误累计八次之后,浮点数寄存器就满了.没地方放就错了. 函数前面 ...

  4. Caliburn.Micro - 框架搭建

    简介:Caliburn.Micro是Caliburn的一个轻量级版本开源架构,可以用于wpf,sliverlight,wp7等,和注重模块化的Prism比起来也有许多优点,具体比较可以参考 此文 ht ...

  5. Android开源项目——设置图文居中的按钮 IconButton

    本文介绍一下一个小众的开源项目--IconButton. 本文原创,转载请注明出处: http://blog.csdn.net/maosidiaoxian/article/details/435602 ...

  6. java中的getStackTrace和printStackTrace的区别

    getStackTrace()返回的是通过getOurStackTrace方法获取的StackTraceElement[]数组,而这个StackTraceElement是ERROR的每一个cause ...

  7. C# 从配置文件中读取/写入信息

    读取: var currMemberID = System.Configuration.ConfigurationManager.AppSettings["tolunaMemberID&qu ...

  8. (线性dp,最大连续和)Max Sequence

    Max Sequence Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 18511   Accepted: 7743 Des ...

  9. mysql 删除数据库中所有的表中的数据,只删database下面所有的表。

    select concat('drop table ',table_name,';') from TABLES where table_schema='数据库名称'; select concat('t ...

  10. iframe调用父页面函数用法举例

    iframe如何调用父页面函数. window.parent.xxxxx();//xxxxx()代表父页面方法具体列子如下,其中包括easyUI的右键和单击事件parent.jspbody部分代码 & ...