精华内容
下载资源
问答
  • C语言和C++中#define的用法 2011-09-22 00:00中国IT实验室佚名 ... define是C语言中的... 预处理命令以“#”号开头,如包含命令#include,宏定义命令#define等。一般都放在源文件的前面,它们称为预处理部分。

    C语言和C++中#define的用法

    2011-09-22 00:00 中国IT实验室 佚名
    关键字:C语言

      define是C语言中的预处理命令,它用于宏定义,可以提高源代码的可读性,为编程提供方便。

      预处理命令以“#”号开头,如包含命令#include,宏定义命令#define等。一般都放在源文件的前面,它们称为预处理部分。

      所谓预处理是指在进行编译之前所作的工作。预处理是C语言的一个重要功能,它由预处理程序负责完成。当对一个源文件进行编译时,系统将自动引用预处理程序对源程序中的预处理部分作处理,处理完毕自动进入对源程序的编译。

      宏的定义在C或C++语言源程序中允许用一个标识符来表示一个字符串,称为“宏”。被定义为“宏”的标识符称为“宏名”。在编译预处理时,对程序中所有出现的“宏名”,都用宏定义中的字符串去代换,这称为“宏代换”或“宏展开”。宏定义是由源程序中的宏定义命令完成的。宏代换是由预处理程序自动完成的。

      在C或C++语言中,“宏”分为有参数和无参数两种。

      无参数宏定义无参数宏就是不带参数,其定义的一般形式为:#define 标识符 字符串“标识符”为所定义的宏名。“字符串”可以是常数、表达式、格式串等。

      例如:#define PI 3.14它的作用是指定标识符PI来代替常数3.14.在编写源程序时,所有用到3.14的地方都可用PI代替,而对源程序作编译时,将先由预处理程序进行宏代换,即用3.14去置换所有的宏名PI,然后再进行编译。

      宏定义是用宏名来表示一个字符串,在宏展开时又以该字符串取代宏名,这只是一种简单的代换,字符串可以是常数,也可以是表达式,预处理程序对它不作任何检查。如有错误,只能在编译已被宏展开后的源程序时发现。

      宏定义不是说明或语句(它是预处理指令),在行末不必加分号,如加上分号则连分号也一起置换。

      下面举一个无参数宏替代常数的例子:#define PI 3.14 #include int main()

      { float r = 1.0;float area = PI*r*r;printf("The area of the circle is %f",area);return 0;}再举一个使用无参数宏替代字符串的例子:#define M (y*y+3*y)

      #include int main()

      { int s,y;printf("input a number: ");scanf("%d",&y);s = 3*M + 4*M + 5*M;printf("s=%d\n",s);return 0;} # define M (y*y+3*y) 定义M表达式(y*y+3*y)。在编写源程序时,所有的(y*y+3*y)都可由M代替,而对源程序作编译时,将先由预处理程序进行宏代换,即用 (y*y+3*y)表达式去置换所有的宏名M,然后再进行编译。

      上例程序中首先进行宏定义,定义M表达式(y*y+3*y),在s= 3*M+4*M+5* M中作了宏调用。在预处理时经宏展开后该语句变为:s=3*(y*y+3*y)+4* (y*y+3*y)+5* (y*y+3*y);但要注意的是,在宏定义中表达式(y*y+3*y)两边的括号不能少。否则会发生错误。

      带参数宏定义C语言允许宏带有参数。在宏定义中的参数称为形式参数,在宏调用中的参数称为实际参数。对带参数的宏,在调用中,不仅要宏展开,而且要用实参去代换形参。

      带参数宏定义的一般形式为:#define 宏名(形参表) 字符串在字符串中含有各个形参。

      带参数宏调用的一般形式为:宏名(实参表)

      例如:#define M(y) y*y+3*y……

      k=M(5);……

      在宏调用时,用实参5去代替形参y,经预处理宏展开后的语句为:k=5*5+3*5举一个具体例子:#define MAX(a,b) (a>b)?a:b #include int main()

      { int x,y,max;printf("input two numbers: ");scanf("%d%d",&x,&y);max = MAX(x,y);printf("max=%d\n",max);return 0;}上例程序的第一行进行带参数宏定义,用宏名MAX表示条件表达式(a>b)?a:b,形参a,b均出现在条件表达式中。程序第七行max = MAX(x, y)为宏调用,实参x,y,将代换形参a,b.宏展开后该语句为: max = (x>y)?x:y;用于计算x,y中的大数。

      对于带参的宏定义有以下问题需要说明:1. 带参宏定义中,宏名和形参表之间不能有空格出现。

      例如把: #define MAX(a,b) (a>b)?a:b写为: #define MAX (a,b) (a>b)?a:b 将被认为是无参宏定义,宏名MAX代表字符串 (a,b)(a>b)?a:b.宏展开时,宏调用语句: max = MAX(x,y);将变为: max = (a,b)(a>b)?a:b(x,y);这显然是错误的。

      2. 在宏定义中的形参是标识符,而宏调用中的实参可以是表达式。

      #define SQ(y) (y)*(y)

      #include int main()

      { int a,sq;printf("input a number: ");scanf("%d",&a);sq=SQ(a+1);printf("sq=%d\n",sq);return 0;}上例中第一行为宏定义,形参为y.程序第七行宏调用中实参为a+1,是一个表达式,在宏展开时,用a+1代换y,再用(y)*(y) 代换SQ,得到如下语句: sq=(a+1)*(a+1); 这与函数的调用是不同的,函数调用时要把实参表达式的值求出来再赋予形参。而宏代换中对实参表达式不作计算直接地照原样代换。

      3. 在宏定义中,字符串内的形参通常要用括号括起来以避免出错。在上例中的宏定义中(y)*(y)表达式的y都用括号括起来,结果是正确的。如果去掉括号,把程序改为以下形式:#define SQ(y) y*y #include int main()

      { int a,sq;printf("input a number: ");scanf("%d",&a);sq=SQ(a+1);printf("sq=%d\n",sq);return 0;}运行结果为:input a number:3 sq=7 (我们期望的结果却是16)。

      问题在哪里呢? 这是由于代换只作符号代换而不作其它处理而造成的。 宏代换后将得到以下语句: sq=a+1*a+1; 由于a为3故sq的值为7.这显然与题意相违,因此参数两边的括号是不能少的。有时候,即使在参数两边加括号还是不够的,请看下面程序:#define SQ(y) (y)*(y)

      #include int main()

      { int a,sq;printf("input a number: ");scanf("%d",&a);sq=160/SQ(a+1);printf("sq=%d\n",sq);return 0;}本程序与前例相比,只把宏调用语句改为: sq=160/SQ(a+1); 运行本程序如输入值仍为3时,希望结果为10.但实际运行的结果如下:input a number:3 sq=160.为什么会得这样的结果呢?分析宏调用语句,在宏代换之后变为: sq=160/(a+1)*(a+1);a为3时,由于“/”和“*”运算符优先级和结合性相同,则先作160/(3+1)得40,再作40*(3+1)最后得160.为了得到正确答案应在宏定义中的整个字符串外加括号,程序修改如下:#define SQ(y) ((y)*(y))

      #include int main()

      { int a,sq;printf("input a number: ");scanf("%d",&a);sq=160/SQ(a+1);printf("sq=%d\n",sq);return 0;}以上讨论说明,对于宏定义,保险的做法是不仅应在参数两侧加括号,也应在整个字符串外加括号。

      4. 带参数的宏和带参函数很相似,但有本质上的不同,把同一表达式用函数处理与用宏处理两者的结果有可能是不同的。

      下面举一个例子进行对比:使用函数:#include int SQ(int);int main()

      { int i=1;while(i<=5)

      printf("%d\n",SQ(i++));return 0;} int SQ(int y)

      { return((y)*(y));}使用宏:#define SQ(y) ((y)*(y))

      #include int main()

      { int i=1;while(i<=5)

      printf("%d\n",SQ(i++));return 0;}在使用函数的例子中函数名为SQ,形参为Y,函数体表达式为((y)*(y))。在使用宏的例子中宏名为SQ,形参也为y,字符串表达式为(y)*(y))。两例表面是相同的,函数调用为SQ(i++),宏调用为SQ(i++),实参也是相同的。但输出结果却大不相同,分析如下:在使用函数的例子中,函数调用是把实参i值传给形参y后自增1.然后输出函数值。因而要循环5次。输出1~5的平方值。而在使用宏的例子中,宏调用时,只作代换。SQ(i++)被代换为((i++)*(i++))。在第一次循环时,由于i等于1,其计算过程为:表达式中前一个i初值为1,然后i自增1变为2,因此表达式中第2个i初值为2,两相乘的结果也为2,然后i值再自增1,得3.在第二次循环时,i值已有初值为3,因此表达式中前一个i为3,后一个i为4,乘积为12,然后i再自增1变为5.进入第三次循环,由于i 值已为5,所以这将是最后一次循环。计算表达式的值为5*6等于30.i值再自增1变为6,不再满足循环条件,停止循环。从以上分析可以看出函数调用和宏调用二者在形式上相似,在本质上是完全不同的。

      "\","#","#@"和"##"在用#define 定义时 , 斜杠("\")是用来续行的,"#"用来把参数转换成字符串,是给参数加上双引号。"##"则用来连接前后两个参数,把它们变成一个字符串,"#@"是给参数加上单引号。下面的例子会使您很容易理解。

      #define Conn(x,y) x##y #define ToChar(a) #@a #define ToString(x) #x

      int n = Conn(123,456); 结果就是n=123456;char* str = Conn("asdf", "adf")结果就是 str = "asdfadf";char a = ToChar(1);结果就是a='1';char* str = ToString(123132);就成了str="123132";为什么需要“#”,“ #@”和“##”这三个操作符呢?原因如下:宏名在源程序中若用引号括起来,则预处理程序不对其作宏代换。如下:#define OK 100 #include int main()

      { printf("OK");printf("\n");return 0;}上例中定义宏名OK表示100,但在printf语句中OK被引号括起来,因此不作宏代换。程序的运行结果为:OK,这表示把“OK”当字符串处理。

      同样,宏名在源程序中若用单引号括起来,则预处理程序也不对其作宏代换。

      宏定义的嵌套宏定义允许嵌套,在宏定义的字符串中可以使用已经定义的宏名。在宏展开时由预处理程序层层代换。例如:#define PI 3.1415926 #define S PI*y*y对语句: printf("%f",s);在宏代换后变为: printf("%f",3.1415926*y*y);结束语使用宏代替一个在程序中经常使用的常量,这样该常量改变时,不用对整个程序进行修改,只修改宏定义的字符串即可,而且当常量比较长时,我们可以用较短的有意义的标识符来写程序,这样更方便一些。举一个大家比较熟悉的例子,圆周率π是在数学上常用的一个值,有时我们会用3.14来表示,有时也会用3.1415926等,这要看计算所需要的精度,如果我们编制的一个程序中要多次使用它,那么需要确定一个数值,在本次运行中不改变,但也许后来发现程序所表现的精度有变化,需要改变它的值,这就需要修改程序中所有的相关数值,这会给我们带来一定的不便,但如果使用宏定义,使用一个标识符来代替,则在修改时只修改宏定义即可,还可以减少输入 3.1415926这样长的数值多次的情况,我们可以如此定义 #define pi 3.1415926,既减少了输入又便于修改,何乐而不为呢?

      另外,使用带参数的宏定义可完成函数调用的功能,又能减少系统开销,提高运行效率。正如C语言中所讲,函数的使用可以使程序更加模块化,便于组织,而且可重复利用,但在发生函数调用时,需要保留调用函数的现场,以便子函数执行结束后能返回继续执行,同样在子函数执行完后要恢复调用函数的现场,这都需要一定的时间,如果子函数执行的操作比较多,这种转换时间开销可以忽略,但如果子函数完成的功能比较少,甚至于只完成一点操作,如一个乘法语句的操作,则这部分转换开销就相对较大了,但使用带参数的宏定义就不会出现这个问题,因为它是在预处理阶段即进行了宏展开,在执行时不需要转换,即在当地执行。宏定义可完成简单的操作,但复杂的操作还是要由函数调用来完成,而且宏定义所占用的目标代码空间相对较大。所以在使用时要依据具体情况来决定是否使用宏定义。

    展开全文
  • 玩转ADB命令(ADB命令使用大全)

    万次阅读 多人点赞 2017-10-27 10:53:39
    我相信做Android开发的朋友都用过ADB命令,但是也只是限于安装应用push文件和设备重启相关,根深的也不知道了,其实我们完全可以了解多一点,有一些不常用的场景我们至少应该知道它可以做到,比如,我们知道adb ...

    此文章内容整合自网络,欢迎转载。

    我相信做Android开发的朋友都用过ADB命令,但是也只是限于安装应用push文件和设备重启相关,更深的就不知道了,其实我们完全可以了解多一点,有一些不常用的场景我们至少应该知道它可以做到,比如,我们知道adb install 却不知道adb shell am start。前者是用来安装软件,后者用来打开软件,后者的一个使用场景让我对他重视:公司定制Android系统,在调试屏幕的时候要看是否满屏验证驱动是否正常,比较麻烦的做法是要拿到Android开发者手里用eclipse或者其他ide安装打开。显然相对于驱动人员连上数据线使用adb命令要复杂得多。因此,了解多一点还是很有必要的。

    接下来可能说的比较繁琐,我尽量说简单点,请耐心看完。

    ADB是什么


    Adb的全称为Android Debug Bridge:android调试桥梁,下图为Android官方对adb的介绍:
    在这里插入图片描述
    可以看出,Android的初衷是用adb这样的一个工具来协助开发人员在开发android应用的过程中更快更好的调试apk,因此adb具有安装卸载apk、拷贝推送文件、查看设备硬件信息、查看应用程序占用资源、在设备执行shell命令等功能;

    我们可以在android sdk安装目录的platform-tools目录下找到adb工具;

    现有安卓系统的权限机制越来越完善,很多希望能够绕开权限管理机制进行的一些操作都已经无法使用,但是Adb却可以实现。实际上Adb在某种程度上有很大权限的,即使是在最新版本的Android系统上。因为Adb的设计初衷是为了方便开发人员调试,因此必然需要暴露一些权限以外的接口。于是很多公司利用这个特性可以绕开权限机制在非Root非定制机上做一些操作(具体用法就是下面说的这些),当然方式也是五花八门,比如通过手机OTG连接,这里不再赘述。

    ADB架构

    为了方便理解,我们从三个指令入手,我们经常会用到adb start-server,adb devices,adb kill-server。
    然后我们经常会看到这样的输出界面:

    C:\Users\dell>adb devices
    List of devices attached
    * daemon not running. starting it now at tcp:5037 *
    * daemon started successfully *
    

    于是这里有三点疑问,为什么是server,server对应的是服务器或者服务端吧?如果手机是客户端,服务端是不是指电脑上开启的服务。还有这个呆萌(daemon )又是啥?

    ADB是一个C/S架构的应用程序,由三部分组成:

    1. 运行在pc端的adb client:
      命令行程序”adb”用于从shell或脚本中运行adb命令。首先,“adb”程序尝试定位主机上的ADB服务器,如果找不到ADB服务器,“adb”程序自动启动一个ADB服务器。接下来,当设备的adbd和pc端的adb server建立连接后,adb client就可以向ADB servcer发送服务请求;
    2. 运行在pc端的adb server:
      ADB Server是运行在主机上的一个后台进程。它的作用在于检测USB端口感知设备的连接和拔除,以及模拟器实例的启动或停止,ADB Server还需要将adb client的请求通过usb或者tcp的方式发送到对应的adbd上;
    3. 运行在设备端的常驻进程adb demon (adbd):
      程序“adbd”作为一个后台进程在Android设备或模拟器系统中运行。它的作用是连接ADB服务器,并且为运行在主机上的客户端提供一些服务;

    在这里插入图片描述

    在这里插入图片描述

    ADB端口被占用

    有小伙伴说希望我把Adb启动问题放在最前面,因为他经常遇到adb找不到设备的问题,那我就放到前面吧,我想肯定不止是她一个人会遇到这种情况。

    5037为adb默认端口,若5037端口被占用,则我们在使用Adb命令的时候会因为找不到设备而困扰,这个问题对于Adb不是很熟悉的小伙伴来说会经常遇到,因此我就把这个用法放在文章开头了,以便于小伙伴能方便找到;
    解决这种端口占用的问题思路都是一样的,三步走:

    1. 找到使用该端口的进程Pid;
    C:\Windows\system32>netstat -aon|findstr 5037
    TCP    127.0.0.1:5037         0.0.0.0:0              LISTENING       3172
    
    1. 通过PID找到对应的进程名(便于定位,可以跳过);
    C:\Windows\system32>tasklist /fi "PID eq 3172"
    
    映像名称                       PID 会话名              会话#       内存使用
    ========================= ======== ================ =========== ============
    360MobileLink.exe             3172 Console                    4     40,208 K
    
    1. 使用命令终止该命令的运行;
    C:\Users\wwx229495>taskkill /pid 3172 /f
    成功: 已终止 PID 为 3172 的进程。
    

    有些时候,一些流氓程序会复制一份Adb.exe到windows环境变量中,比如C://Windows/system32,这个时候我们可以使用Where
    Adb 命令找出来adb所在的路径并删除。

    基本用法


    adb能做什么?答案是所有能对手机的操作都能用adb实现。也就是说如果你玩的6,你就是触摸屏完全坏了,显示屏完全坏了,就只是给你一个主板,你照样能完成你要做的动作。当然在一般场景不推荐这样做,效率优先嘛。

    接下来的内容是转自github上一位大牛的博客,如有侵权请告知,立即删除;
    后期

    命令语法

    adb 命令的基本语法如下:

    adb [-d|-e|-s ]

    如果只有一个设备/模拟器连接时,可以省略掉 [-d|-e|-s ] 这一部分,直接使用 adb 。

    为命令指定目标设备

    如果有多个设备/模拟器连接,则需要为命令指定目标设备。

    参数含义
    -d指定当前唯一通过 USB 连接的 Android 设备为命令目标
    -e指定当前唯一运行的模拟器为命令目标
    -s <serialNumber>指定相应 serialNumber 号的设备/模拟器为命令目标

    在多个设备/模拟器连接的情况下较常用的是 -s 参数,serialNumber 可以通过 adb devices 命令获取。如:

    $ adb devices
    
    List of devices attached
    cf264b8f	device
    emulator-5554	device
    10.129.164.6:5555	device
    

    输出里的 cf264b8f、emulator-5554 和 10.129.164.6:5555 即为 serialNumber。

    比如这时想指定 cf264b8f 这个设备来运行 adb 命令获取屏幕分辨率:

    adb -s cf264b8f shell wm size
    

    又如想给 10.129.164.6:5555 这个设备安装应用(这种形式的 serialNumber 格式为 :,一般为无线连接的设备或 Genymotion 等第三方 Android 模拟器):

    adb -s 10.129.164.6:5555 install test.apk
    

    遇到多设备/模拟器的情况均使用这几个参数为命令指定目标设备,下文中为简化描述,不再重复。

    启动/停止

    启动 adb server 命令:

    adb start-server
    

    (一般无需手动执行此命令,在运行 adb 命令时若发现 adb server 没有启动会自动调起。)

    停止 adb server 命令:

    adb kill-server
    

    查看 adb 版本

    adb version
    

    示例输出

    Android Debug Bridge version 1.0.36
    Revision 8f855a3d9b35-android
    

    以 root 权限运行 adbd

    adb 的运行原理是 PC 端的 adb server 与手机端的守护进程 adbd 建立连接,然后 PC 端的 adb client 通过 adb server 转发命令,adbd 接收命令后解析运行。

    所以如果 adbd 以普通权限执行,有些需要 root 权限才能执行的命令无法直接用 adb xxx 执行。这时可以 adb shell 然后 su 后执行命令,也可以让 adbd 以 root 权限执行,这个就能随意执行高权限命令了。

    命令:

    adb root
    

    正常输出:

    restarting adbd as root
    

    现在再运行 adb shell,看看命令行提示符是不是变成 # 了?

    有些手机 root 后也无法通过 adb root 命令让 adbd 以 root 权限执行,比如三星的部分机型,会提示 adbd cannot run as root in production builds,此时可以先安装 adbd Insecure,然后 adb root 试试。

    相应地,如果要恢复 adbd 为非 root 权限的话,可以使用 adb unroot 命令。

    指定 adb server 的网络端口

    adb -P <port> start-server
    

    默认端口为 5037。

    设备连接管理


    查询已连接设备/模拟器

    命令:

    adb devices
    

    输出示例:

    List of devices attached
    cf264b8f	device
    emulator-5554	device
    10.129.164.6:5555	device
    

    输出格式为 [serialNumber] [state],serialNumber 即我们常说的 SN,state 有如下几种:

    offline —— 表示设备未连接成功或无响应。

    device —— 设备已连接。注意这个状态并不能标识 Android 系统已经完全启动和可操作,在设备启动过程中设备实例就可连接到 adb,但启动完毕后系统才处于可操作状态。

    no device —— 没有设备/模拟器连接。

    以上输出显示当前已经连接了三台设备/模拟器,cf264b8f、emulator-5554 和 10.129.164.6:5555 分别是它们的 SN。从 emulator-5554 这个名字可以看出它是一个 Android 模拟器,而 10.129.164.6:5555 这种形为 : 的 serialNumber 一般是无线连接的设备或 Genymotion 等第三方 Android 模拟器。

    常见异常输出:

    没有设备/模拟器连接成功。

    List of devices attached
    设备/模拟器未连接到 adb 或无响应。

    List of devices attached
    cf264b8f offline

    USB 连接

    通过 USB 连接来正常使用 adb 需要保证几点:

    硬件状态正常。

    包括 Android 设备处于正常开机状态,USB 连接线和各种接口完好。

    Android 设备的开发者选项和 USB 调试模式已开启。

    可以到「设置」-「开发者选项」-「Android 调试」查看。

    如果在设置里找不到开发者选项,那需要通过一个彩蛋来让它显示出来:在「设置」-「关于手机」连续点击「版本号」7 次。

    设备驱动状态正常。

    这一点貌似在 Linux 和 Mac OS X 下不用操心,在 Windows 下有可能遇到需要安装驱动的情况,确认这一点可以右键「计算机」-「属性」,到「设备管理器」里查看相关设备上是否有黄色感叹号或问号,如果没有就说明驱动状态已经好了。否则可以下载一个手机助手类程序来安装驱动先。

    通过 USB 线连接好电脑和设备后确认状态。

    adb devices
    

    如果能看到
    xxxxxx device
    说明连接成功。

    无线连接(需要借助 USB 线)

    除了可以通过 USB 连接设备与电脑来使用 adb,也可以通过无线连接——虽然连接过程中也有需要使用 USB 的步骤,但是连接成功之后你的设备就可以在一定范围内摆脱 USB 连接线的限制啦!

    操作步骤:
    将 Android 设备与要运行 adb 的电脑连接到同一个局域网,比如连到同一个 WiFi。
    将设备与电脑通过 USB 线连接。
    应确保连接成功(可运行 adb devices 看是否能列出该设备)。
    让设备在 5555 端口监听 TCP/IP 连接:

    adb tcpip 5555
    

    断开 USB 连接。
    找到设备的 IP 地址。
    一般能在「设置」-「关于手机」-「状态信息」-「IP地址」找到,也可以使用下文里 查看设备信息 - IP 地址 一节里的方法用 adb 命令来查看。

    通过 IP 地址连接设备。

    adb connect <device-ip-address>
    

    这里的 就是上一步中找到的设备 IP 地址。

    确认连接状态。

    adb devices
    

    如果能看到

    <device-ip-address>:5555 device
    

    说明连接成功。
    如果连接不了,请确认 Android 设备与电脑是连接到了同一个 WiFi,然后再次执行 adb connect <device-ip-address> 那一步;
    如果还是不行的话,通过 adb kill-server 重新启动 adb 然后从头再来一次试试。

    断开无线连接
    命令:

    adb disconnect <device-ip-address>
    

    无线连接(无需借助 USB 线)

    注:需要 root 权限。

    上一节「无线连接(需要借助 USB 线)」是官方文档里介绍的方法,需要借助于 USB 数据线来实现无线连接。
    既然我们想要实现无线连接,那能不能所有步骤下来都是无线的呢?答案是能的。
    在 Android 设备上安装一个终端模拟器。
    已经安装过的设备可以跳过此步。我使用的终端模拟器下载地址是:Terminal Emulator for Android Downloads
    将 Android 设备与要运行 adb 的电脑连接到同一个局域网,比如连到同一个 WiFi。
    打开 Android 设备上的终端模拟器,在里面依次运行命令:

    su
    setprop service.adb.tcp.port 5555
    

    找到 Android 设备的 IP 地址。

    一般能在「设置」-「关于手机」-「状态信息」-「IP地址」找到,也可以使用下文里 查看设备信息 - IP 地址 一节里的方法用 adb 命令来查看。

    在电脑上通过 adb 和 IP 地址连接 Android 设备。

    adb connect <device-ip-address>
    

    这里的 就是上一步中找到的设备 IP 地址。

    如果能看到 connected to :5555 这样的输出则表示连接成功。

    节注一:

    有的设备,比如小米 5S + MIUI 8.0 + Android 6.0.1 MXB48T,可能在第 5 步之前需要重启 adbd 服务,在设备的终端模拟器上运行:

    restart adbd
    

    如果 restart 无效,尝试以下命令:

    stop adbd
    start adbd
    

    应用管理

    查看应用列表

    查看应用列表的基本命令格式是

    adb shell pm list packages [-f] [-d] [-e] [-s] [-3] [-i] [-u] [--user USER_ID] [FILTER]
    

    即在 adb shell pm list packages 的基础上可以加一些参数进行过滤查看不同的列表,支持的过滤参数如下:

    参数显示列表
    所有应用
    -f显示应用关联的 apk 文件
    -d只显示 disabled 的应用
    -e只显示 enabled 的应用
    -s只显示系统应用
    -3只显示第三方应用
    -i显示应用的 installer
    -u包含已卸载应用
    <FILTER>包名包含 <FILTER> 字符串

    所有应用

    命令:

    adb shell pm list packages
    

    输出示例:

    package:com.android.smoketest
    package:com.example.android.livecubes
    package:com.android.providers.telephony
    package:com.google.android.googlequicksearchbox
    package:com.android.providers.calendar
    package:com.android.providers.media
    package:com.android.protips
    package:com.android.documentsui
    package:com.android.gallery
    package:com.android.externalstorage
    ...
    // other packages here
    ...
    

    系统应用

    命令:

    adb shell pm list packages -s
    

    第三方应用

    命令:

    adb shell pm list packages -3
    

    包名包含某字符串的应用
    比如要查看包名包含字符串 mazhuang 的应用列表,命令:

    adb shell pm list packages mazhuang
    

    当然也可以使用 grep 来过滤:

    adb shell pm list packages | grep mazhuang
    

    安装 APK

    命令格式:

    adb install [-lrtsdg] <path_to_apk>
    

    参数:

    adb install 后面可以跟一些可选参数来控制安装 APK 的行为,可用参数及含义如下:

    参数含义
    -l将应用安装到保护目录 /mnt/asec
    -r允许覆盖安装
    -t允许安装 AndroidManifest.xml 里 application 指定 android:testOnly="true" 的应用
    -s将应用安装到 sdcard
    -d允许降级覆盖安装
    -g授予所有运行时权限

    运行命令后如果见到类似如下输出(状态为 Success)代表安装成功:

    [100%] /data/local/tmp/1.apk
    	pkg: /data/local/tmp/1.apk
    Success
    

    上面是当前最新版 v1.0.36 的 adb 的输出,会显示 push apk 文件到手机的进度百分比。

    使用旧版本 adb 的输出则是这样的:

    12040 KB/s (22205609 bytes in 1.801s)
            pkg: /data/local/tmp/SogouInput_android_v8.3_sweb.apk
    Success
    

    而如果状态为 Failure 则表示安装失败,比如:

    [100%] /data/local/tmp/map-20160831.apk
            pkg: /data/local/tmp/map-20160831.apk
    Failure [INSTALL_FAILED_ALREADY_EXISTS]
    

    常见安装失败输出代码、含义及可能的解决办法如下:

    输出含义解决办法
    INSTALL_FAILED_ALREADY_EXISTS应用已经存在,或卸载了但没卸载干净adb install 时使用 -r 参数,或者先 adb uninstall <packagename> 再安装
    INSTALL_FAILED_INVALID_APK无效的 APK 文件
    INSTALL_FAILED_INVALID_URI无效的 APK 文件名确保 APK 文件名里无中文
    INSTALL_FAILED_INSUFFICIENT_STORAGE空间不足清理空间
    INSTALL_FAILED_DUPLICATE_PACKAGE已经存在同名程序
    INSTALL_FAILED_NO_SHARED_USER请求的共享用户不存在
    INSTALL_FAILED_UPDATE_INCOMPATIBLE以前安装过同名应用,但卸载时数据没有移除;或者已安装该应用,但签名不一致adb uninstall <packagename> 再安装
    INSTALL_FAILED_SHARED_USER_INCOMPATIBLE请求的共享用户存在但签名不一致
    INSTALL_FAILED_MISSING_SHARED_LIBRARY安装包使用了设备上不可用的共享库
    INSTALL_FAILED_REPLACE_COULDNT_DELETE替换时无法删除
    INSTALL_FAILED_DEXOPTdex 优化验证失败或空间不足
    INSTALL_FAILED_OLDER_SDK设备系统版本低于应用要求
    INSTALL_FAILED_CONFLICTING_PROVIDER设备里已经存在与应用里同名的 content provider
    INSTALL_FAILED_NEWER_SDK设备系统版本高于应用要求
    INSTALL_FAILED_TEST_ONLY应用是 test-only 的,但安装时没有指定 -t 参数
    INSTALL_FAILED_CPU_ABI_INCOMPATIBLE包含不兼容设备 CPU 应用程序二进制接口的 native code
    INSTALL_FAILED_MISSING_FEATURE应用使用了设备不可用的功能
    INSTALL_FAILED_CONTAINER_ERROR1. sdcard 访问失败;
    2. 应用签名与 ROM 签名一致,被当作内置应用。
    1. 确认 sdcard 可用,或者安装到内置存储;
    2. 打包时不与 ROM 使用相同签名。
    INSTALL_FAILED_INVALID_INSTALL_LOCATION1. 不能安装到指定位置;
    2. 应用签名与 ROM 签名一致,被当作内置应用。
    1. 切换安装位置,添加或删除 -s 参数;
    2. 打包时不与 ROM 使用相同签名。
    INSTALL_FAILED_MEDIA_UNAVAILABLE安装位置不可用一般为 sdcard,确认 sdcard 可用或安装到内置存储
    INSTALL_FAILED_VERIFICATION_TIMEOUT验证安装包超时
    INSTALL_FAILED_VERIFICATION_FAILURE验证安装包失败
    INSTALL_FAILED_PACKAGE_CHANGED应用与调用程序期望的不一致
    INSTALL_FAILED_UID_CHANGED以前安装过该应用,与本次分配的 UID 不一致清除以前安装过的残留文件
    INSTALL_FAILED_VERSION_DOWNGRADE已经安装了该应用更高版本使用 -d 参数
    INSTALL_FAILED_PERMISSION_MODEL_DOWNGRADE已安装 target SDK 支持运行时权限的同名应用,要安装的版本不支持运行时权限
    INSTALL_PARSE_FAILED_NOT_APK指定路径不是文件,或不是以 .apk 结尾
    INSTALL_PARSE_FAILED_BAD_MANIFEST无法解析的 AndroidManifest.xml 文件
    INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION解析器遇到异常
    INSTALL_PARSE_FAILED_NO_CERTIFICATES安装包没有签名
    INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES已安装该应用,且签名与 APK 文件不一致先卸载设备上的该应用,再安装
    INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING解析 APK 文件时遇到 CertificateEncodingException
    INSTALL_PARSE_FAILED_BAD_PACKAGE_NAMEmanifest 文件里没有或者使用了无效的包名
    INSTALL_PARSE_FAILED_BAD_SHARED_USER_IDmanifest 文件里指定了无效的共享用户 ID
    INSTALL_PARSE_FAILED_MANIFEST_MALFORMED解析 manifest 文件时遇到结构性错误
    INSTALL_PARSE_FAILED_MANIFEST_EMPTY在 manifest 文件里找不到找可操作标签(instrumentation 或 application)
    INSTALL_FAILED_INTERNAL_ERROR因系统问题安装失败
    INSTALL_FAILED_USER_RESTRICTED用户被限制安装应用
    INSTALL_FAILED_DUPLICATE_PERMISSION应用尝试定义一个已经存在的权限名称
    INSTALL_FAILED_NO_MATCHING_ABIS应用包含设备的应用程序二进制接口不支持的 native code
    INSTALL_CANCELED_BY_USER应用安装需要在设备上确认,但未操作设备或点了取消在设备上同意安装
    INSTALL_FAILED_ACWF_INCOMPATIBLE应用程序与设备不兼容
    does not contain AndroidManifest.xml无效的 APK 文件
    is not a valid zip file无效的 APK 文件
    Offline设备未连接成功先将设备与 adb 连接成功
    unauthorized设备未授权允许调试
    error: device not found没有连接成功的设备先将设备与 adb 连接成功
    protocol failure设备已断开连接先将设备与 adb 连接成功
    Unknown option: -sAndroid 2.2 以下不支持安装到 sdcard不使用 -s 参数
    No space left on device空间不足清理空间
    Permission denied ... sdcard ...sdcard 不可用
    signatures do not match the previously installed version; ignoring!已安装该应用且签名不一致先卸载设备上的该应用,再安装

    参考:[PackageManager.java]

    adb install 内部原理简介

    adb install 实际是分三步完成:

    1. push apk 文件到 /data/local/tmp。
    2. 调用 pm install 安装。
    3. 删除 /data/local/tmp 下的对应 apk 文件。

    所以,必要的时候也可以根据这个步骤,手动分步执行安装过程。

    卸载应用

    命令:

    adb uninstall [-k] <packagename>
    

    <packagename> 表示应用的包名,-k 参数可选,表示卸载应用但保留数据和缓存目录。
    命令示例:

    adb uninstall com.qihoo360.mobilesafe
    

    表示卸载 360 手机卫士。

    清除应用数据与缓存

    命令:

    adb shell pm clear <packagename>
    

    <packagename> 表示应用名包,这条命令的效果相当于在设置里的应用信息界面点击了「清除缓存」和「清除数据」。

    命令示例:

    adb shell pm clear com.qihoo360.mobilesafe
    

    表示清除 360 手机卫士的数据和缓存。

    查看前台 Activity

    命令:

    adb shell dumpsys activity activities | grep mFocusedActivity
    

    输出示例:

    mFocusedActivity: ActivityRecord{8079d7e u0 com.cyanogenmod.trebuchet/com.android.launcher3.Launcher t42}
    

    其中的 com.cyanogenmod.trebuchet/com.android.launcher3.Launcher 就是当前处于前台的 Activity。

    查看正在运行的 Services

    命令:

    adb shell dumpsys activity services [<packagename>]
    

    <packagename> 参数不是必须的,指定 <packagename> 表示查看与某个包名相关的 Services,不指定表示查看所有 Services。

    <packagename> 不一定要给出完整的包名,比如运行 adb shell dumpsys activity services org.mazhuang,那么包名 org.mazhuang.demo1、org.mazhuang.demo2 和 org.mazhuang123 等相关的 Services 都会列出来。

    查看应用详细信息

    命令:

    adb shell dumpsys package <packagename>
    

    输出中包含很多信息,包括 Activity Resolver Table、Registered ContentProviders、包名、userId、安装后的文件资源代码等路径、版本信息、权限信息和授予状态、签名版本信息等。

    <packagename> 表示应用包名。

    输出示例:

    Activity Resolver Table:
      Non-Data Actions:
          android.intent.action.MAIN:
            5b4cba8 org.mazhuang.guanggoo/.SplashActivity filter 5ec9dcc
              Action: "android.intent.action.MAIN"
              Category: "android.intent.category.LAUNCHER"
              AutoVerify=false
    
    Registered ContentProviders:
      org.mazhuang.guanggoo/com.tencent.bugly.beta.utils.BuglyFileProvider:
        Provider{7a3c394 org.mazhuang.guanggoo/com.tencent.bugly.beta.utils.BuglyFileProvider}
    
    ContentProvider Authorities:
      [org.mazhuang.guanggoo.fileProvider]:
        Provider{7a3c394 org.mazhuang.guanggoo/com.tencent.bugly.beta.utils.BuglyFileProvider}
          applicationInfo=ApplicationInfo{7754242 org.mazhuang.guanggoo}
    
    Key Set Manager:
      [org.mazhuang.guanggoo]
          Signing KeySets: 501
    
    Packages:
      Package [org.mazhuang.guanggoo] (c1d7f):
        userId=10394
        pkg=Package{55f714c org.mazhuang.guanggoo}
        codePath=/data/app/org.mazhuang.guanggoo-2
        resourcePath=/data/app/org.mazhuang.guanggoo-2
        legacyNativeLibraryDir=/data/app/org.mazhuang.guanggoo-2/lib
        primaryCpuAbi=null
        secondaryCpuAbi=null
        versionCode=74 minSdk=15 targetSdk=25
        versionName=1.1.74
        splits=[base]
        apkSigningVersion=2
        applicationInfo=ApplicationInfo{7754242 org.mazhuang.guanggoo}
        flags=[ HAS_CODE ALLOW_CLEAR_USER_DATA ALLOW_BACKUP ]
        privateFlags=[ RESIZEABLE_ACTIVITIES ]
        dataDir=/data/user/0/org.mazhuang.guanggoo
        supportsScreens=[small, medium, large, xlarge, resizeable, anyDensity]
        timeStamp=2017-10-22 23:50:53
        firstInstallTime=2017-10-22 23:50:25
        lastUpdateTime=2017-10-22 23:50:55
        installerPackageName=com.miui.packageinstaller
        signatures=PackageSignatures{af09595 [53c7caa2]}
        installPermissionsFixed=true installStatus=1
        pkgFlags=[ HAS_CODE ALLOW_CLEAR_USER_DATA ALLOW_BACKUP ]
        requested permissions:
          android.permission.READ_PHONE_STATE
          android.permission.INTERNET
          android.permission.ACCESS_NETWORK_STATE
          android.permission.ACCESS_WIFI_STATE
          android.permission.READ_LOGS
          android.permission.WRITE_EXTERNAL_STORAGE
          android.permission.READ_EXTERNAL_STORAGE
        install permissions:
          android.permission.INTERNET: granted=true
          android.permission.ACCESS_NETWORK_STATE: granted=true
          android.permission.ACCESS_WIFI_STATE: granted=true
        User 0: ceDataInode=1155675 installed=true hidden=false suspended=false stopped=true notLaunched=false enabled=0
          gids=[3003]
          runtime permissions:
            android.permission.READ_EXTERNAL_STORAGE: granted=true
            android.permission.READ_PHONE_STATE: granted=true
            android.permission.WRITE_EXTERNAL_STORAGE: granted=true
        User 999: ceDataInode=0 installed=false hidden=false suspended=false stopped=true notLaunched=true enabled=0
          gids=[3003]
          runtime permissions:
    
    
    Dexopt state:
      [org.mazhuang.guanggoo]
        Instruction Set: arm64
          path: /data/app/org.mazhuang.guanggoo-2/base.apk
          status: /data/app/org.mazhuang.guanggoo-2/oat/arm64/base.odex [compilation_filter=speed-profile, status=kOatUpToDa
          te]
    

    与应用交互

    主要是使用 am <command> 命令,常用的 <command> 如下:

    command用途
    start [options] <INTENT>启动 <INTENT> 指定的 Activity
    startservice [options] <INTENT>启动 <INTENT> 指定的 Service
    broadcast [options] <INTENT>发送 <INTENT> 指定的广播
    force-stop <packagename>停止 <packagename> 相关的进程

    <INTENT> 参数很灵活,和写 Android 程序时代码里的 Intent 相对应。

    用于决定 intent 对象的选项如下:

    参数含义
    -a <ACTION>指定 action,比如 android.intent.action.VIEW
    -c <CATEGORY>指定 category,比如 android.intent.category.APP_CONTACTS
    -n <COMPONENT>指定完整 component 名,用于明确指定启动哪个 Activity,如 com.example.app/.ExampleActivity

    <INTENT> 里还能带数据,就像写代码时的 Bundle 一样:

    参数含义
    --esn <EXTRA_KEY>null 值(只有 key 名)
    `-e--es <EXTRA_KEY> <EXTRA_STRING_VALUE>`
    --ez <EXTRA_KEY> <EXTRA_BOOLEAN_VALUE>boolean 值
    --ei <EXTRA_KEY> <EXTRA_INT_VALUE>integer 值
    --el <EXTRA_KEY> <EXTRA_LONG_VALUE>long 值
    --ef <EXTRA_KEY> <EXTRA_FLOAT_VALUE>float 值
    --eu <EXTRA_KEY> <EXTRA_URI_VALUE>URI
    --ecn <EXTRA_KEY> <EXTRA_COMPONENT_NAME_VALUE>component name
    --eia <EXTRA_KEY> <EXTRA_INT_VALUE>[,<EXTRA_INT_VALUE...]integer 数组
    --ela <EXTRA_KEY> <EXTRA_LONG_VALUE>[,<EXTRA_LONG_VALUE...]long 数组

    调起 Activity

    命令格式:

    adb shell am start [options] <INTENT>
    

    例如:

    adb shell am start -n com.tencent.mm/.ui.LauncherUI
    

    表示调起微信主界面。

    adb shell am start -n org.mazhuang.boottimemeasure/.MainActivity --es "toast" "hello, world"
    

    表示调起 org.mazhuang.boottimemeasure/.MainActivity 并传给它 string 数据键值对 toast - hello, world。

    调起 Service

    命令格式:

    adb shell am startservice [options] <INTENT>
    

    例如:

    adb shell am startservice -n com.tencent.mm/.plugin.accountsync.model.AccountAuthenticatorService
    

    表示调起微信的某 Service。

    发送广播

    命令格式:

    adb shell am broadcast [options] <INTENT>
    

    可以向所有组件广播,也可以只向指定组件广播。

    例如,向所有组件广播 BOOT_COMPLETED:

    adb shell am broadcast -a android.intent.action.BOOT_COMPLETED
    

    又例如,只向 org.mazhuang.boottimemeasure/.BootCompletedReceiver 广播 BOOT_COMPLETED:

    adb shell am broadcast -a android.intent.action.BOOT_COMPLETED -n org.mazhuang.boottimemeasure/.BootCompletedReceiver
    

    这类用法在测试的时候很实用,比如某个广播的场景很难制造,可以考虑通过这种方式来发送广播。
    既能发送系统预定义的广播,也能发送自定义广播。如下是部分系统预定义广播及正常触发时机:

    action触发时机
    android.net.conn.CONNECTIVITY_CHANGE网络连接发生变化
    android.intent.action.SCREEN_ON屏幕点亮
    android.intent.action.SCREEN_OFF屏幕熄灭
    android.intent.action.BATTERY_LOW电量低,会弹出电量低提示框
    android.intent.action.BATTERY_OKAY电量恢复了
    android.intent.action.BOOT_COMPLETED设备启动完毕
    android.intent.action.DEVICE_STORAGE_LOW存储空间过低
    android.intent.action.DEVICE_STORAGE_OK存储空间恢复
    android.intent.action.PACKAGE_ADDED安装了新的应用
    android.net.wifi.STATE_CHANGEWiFi 连接状态发生变化
    android.net.wifi.WIFI_STATE_CHANGEDWiFi 状态变为启用/关闭/正在启动/正在关闭/未知
    android.intent.action.BATTERY_CHANGED电池电量发生变化
    android.intent.action.INPUT_METHOD_CHANGED系统输入法发生变化
    android.intent.action.ACTION_POWER_CONNECTED外部电源连接
    android.intent.action.ACTION_POWER_DISCONNECTED外部电源断开连接
    android.intent.action.DREAMING_STARTED系统开始休眠
    android.intent.action.DREAMING_STOPPED系统停止休眠
    android.intent.action.WALLPAPER_CHANGED壁纸发生变化
    android.intent.action.HEADSET_PLUG插入耳机
    android.intent.action.MEDIA_UNMOUNTED卸载外部介质
    android.intent.action.MEDIA_MOUNTED挂载外部介质
    android.os.action.POWER_SAVE_MODE_CHANGED省电模式开启

    (以上广播均可使用 adb 触发)

    强制停止应用

    命令:

    adb shell am force-stop <packagename>
    

    命令示例:

    adb shell am force-stop com.qihoo360.mobilesafe
    

    表示停止 360 安全卫士的一切进程与服务。

    禁用应用和启动

    命令示例:

    adb shell  pm disable-user  <packagename>
    adb shell pm disable <packagename>
    
    adb shell pm disable-user [options] <packagename>
    

    命令示例:

    adb shell pm enable  <packagename>
    

    撤消应用程序的权限

    1. 向应用授予权限。只能授予应用程序声明的可选权限
    adb shell pm grant <packagename> <PACKAGE_PERMISSION>
    

    例如:adb -d shell pm grant packageName android.permission.BATTERY_STATS

    1. 取消应用授权
    adb shell pm revoke <packagename> <PACKAGE_PERMISSION>
    

    选项--user user_id:要禁用的用户比如,向应用授予权限。在运行Android 6.0(API级别23)及更高版本的设备上,该权限可以是应用清单中声明的​​任何权限。在运行Android 5.1(API级别22)及更低版本的设备上,必须是应用程序定义的可选权限。

    免责声明:以上命令为非常规命令,对于您的设备的任何损坏,强行停止等,我概不负责。您正在对您的设备执行此操作,您自己承担责任。

    文件管理

    复制设备里的文件到电脑

    命令:

    adb pull <设备里的文件路径> [电脑上的目录]
    

    其中 电脑上的目录 参数可以省略,默认复制到当前目录。

    例:

    adb pull /sdcard/sr.mp4 ~/tmp/
    

    *小技巧:*设备上的文件路径可能需要 root 权限才能访问,如果你的设备已经 root 过,可以先使用 adb shell 和 su 命令在 adb shell 里获取 root 权限后,先 cp /path/on/device /sdcard/filename 将文件复制到 sdcard,然后 adb pull /sdcard/filename /path/on/pc。

    复制电脑里的文件到设备

    命令:

    adb push <电脑上的文件路径> <设备里的目录>
    

    例:

    adb push ~/sr.mp4 /sdcard/
    

    *小技巧:*设备上的文件路径普通权限可能无法直接写入,如果你的设备已经 root 过,可以先 adb push /path/on/pc /sdcard/filename,然后 adb shell 和 su 在 adb shell 里获取 root 权限后,cp /sdcard/filename /path/on/device。

    模拟按键/输入

    在 adb shell 里有个很实用的命令叫 input,通过它可以做一些有趣的事情。
    input 命令的完整 help 信息如下:

    Usage: input [<source>] <command> [<arg>...]
    
    The sources are:
          mouse
          keyboard
          joystick
          touchnavigation
          touchpad
          trackball
          stylus
          dpad
          gesture
          touchscreen
          gamepad
    
    The commands and default sources are:
          text <string> (Default: touchscreen)
          keyevent [--longpress] <key code number or name> ... (Default: keyboard)
          tap <x> <y> (Default: touchscreen)
          swipe <x1> <y1> <x2> <y2> [duration(ms)] (Default: touchscreen)
          press (Default: trackball)
          roll <dx> <dy> (Default: trackball)
    

    比如模拟点击://在屏幕上点击坐标点x=50 y=250的位置。

    adb shell input tap 50 250

    比如使用 adb shell input keyevent 命令,不同的 keycode 能实现不同的功能,完整的 keycode 列表详见 KeyEvent,摘引部分我觉得有意思的如下:

    keycode含义
    3HOME 键
    4返回键
    5打开拨号应用
    6挂断电话
    24增加音量
    25降低音量
    26电源键
    27拍照(需要在相机应用里)
    64打开浏览器
    82菜单键
    85播放/暂停
    86停止播放
    87播放下一首
    88播放上一首
    122移动光标到行首或列表顶部
    123移动光标到行末或列表底部
    126恢复播放
    127暂停播放
    164静音
    176打开系统设置
    187切换应用
    207打开联系人
    208打开日历
    209打开音乐
    210打开计算器
    220降低屏幕亮度
    221提高屏幕亮度
    223系统休眠
    224点亮屏幕
    231打开语音助手
    276如果没有 wakelock 则让系统休眠

    下面是 input 命令的一些用法举例。

    电源键

    db shell input keyevent 26
    

    执行效果相当于按电源键。

    菜单键

    命令:

    adb shell input keyevent 82
    

    HOME 键

    命令:

    adb shell input keyevent 3
    

    返回键

    命令:

    adb shell input keyevent 4
    

    音量控制

    增加音量:

    adb shell input keyevent 24
    

    降低音量:

    adb shell input keyevent 25
    

    静音:

    adb shell input keyevent 164
    

    媒体控制

    播放/暂停:

    adb shell input keyevent 85
    

    停止播放:

    adb shell input keyevent 86
    

    播放下一首:

    adb shell input keyevent 87
    

    播放上一首:

    adb shell input keyevent 88
    

    恢复播放:

    adb shell input keyevent 126
    

    暂停播放:

    adb shell input keyevent 127
    

    点亮/熄灭屏幕

    可以通过上文讲述过的模拟电源键来切换点亮和熄灭屏幕,但如果明确地想要点亮或者熄灭屏幕,那可以使用如下方法。

    点亮屏幕:

    adb shell input keyevent 224
    

    熄灭屏幕:

    adb shell input keyevent 223
    

    滑动解锁

    如果锁屏没有密码,是通过滑动手势解锁,那么可以通过 input swipe 来解锁。

    命令(参数以机型 Nexus 5,向上滑动手势解锁举例):

    adb shell input swipe 300 1000 300 500
    

    参数 300 1000 300 500 分别表示起始点x坐标 起始点y坐标 结束点x坐标 结束点y坐标。

    输入文本

    在焦点处于某文本框时,可以通过 input 命令来输入文本。

    命令:

    adb shell input text hello
    

    现在 hello 出现在文本框了。

    查看日志

    Android 系统的日志分为两部分,底层的 Linux 内核日志输出到 /proc/kmsg,Android 的日志输出到 /dev/log。

    Android 日志

    命令格式:

    [adb] logcat [<option>] ... [<filter-spec>] ...
    

    常用用法列举如下:

    按级别过滤日志

    Android 的日志分为如下几个优先级(priority):

    • V —— Verbose(最低,输出得最多)
    • D —— Debug I —— Info
    • W —— Warning
    • E —— Error
    • F—— Fatal
    • S —— Silent(最高,啥也不输出)

    按某级别过滤日志则会将该级别及以上的日志输出。

    比如,命令:

    adb logcat *:W
    

    会将 Warning、Error、Fatal 和 Silent 日志输出。

    (注: 在 macOS 下需要给 :W 这样以 * 作为 tag 的参数加双引号,如 adb logcat ":W",不然会报错 no matches found: *:W。)

    按 tag 和级别过滤日志

    <filter-spec> 可以由多个 <tag>[:priority] 组成。

    比如,命令:

    adb logcat ActivityManager:I MyApp:D *:S
    

    表示输出 tag ActivityManager 的 Info 以上级别日志,输出 tag MyApp 的 Debug 以上级别日志,及其它 tag 的 Silent 级别日志(即屏蔽其它 tag 日志)。

    日志格式

    可以用 adb logcat -v <format> 选项指定日志输出格式。

    日志支持按以下几种 <format>

    • brief

      默认格式。格式为:

       <priority>/<tag>(<pid>): <message>
      

    示例:

    	D/HeadsetStateMachine( 1785): Disconnected process message: 10, size: 0
    
    • process

      格式为:

       <priority>(<pid>) <message>
      

    示例:

    	D( 1785) Disconnected process message: 10, size: 0  (HeadsetStateMachine)
    
    • tag

      格式为:

       <priority>/<tag>: <message>
      

    示例:

    	D/HeadsetStateMachine: Disconnected process message: 10, size: 0 
    
    • raw

      格式为:

       <message>
      

      示例:

       Disconnected process message: 10, size: 0 
      
    • time

      格式为:

       <datetime> <priority>/<tag>(<pid>): <message>
      

      示例:

       08-28 22:39:39.974 D/HeadsetStateMachine( 1785): Disconnected process message: 10, size: 0
      
    • threadtime

      格式为:

       <datetime> <pid> <tid> <priority> <tag>: <message>
      

      示例:

       08-28 22:39:39.974  1785  1832 D HeadsetStateMachine: Disconnected process message: 10, size: 0
      
    • long

      格式为:

       [ <datetime> <pid>:<tid> <priority>/<tag> ]	<message>
      

    示例:

    	[ 08-28 22:39:39.974  1785: 1832 D/HeadsetStateMachine ] Disconnected process message: 10, size: 0
    

    指定格式可与上面的过滤同时使用。比如:

    adb logcat -v long ActivityManager:I *:S
    

    清空日志

    adb logcat -c
    

    内核日志

    命令:

    adb shell dmesg
    

    输出示例:

    <6>[14201.684016] PM: noirq resume of devices complete after 0.982 msecs
    <6>[14201.685525] PM: early resume of devices complete after 0.838 msecs
    <6>[14201.753642] PM: resume of devices complete after 68.106 msecs
    <4>[14201.755954] Restarting tasks ... done.
    <6>[14201.771229] PM: suspend exit 2016-08-28 13:31:32.679217193 UTC
    <6>[14201.872373] PM: suspend entry 2016-08-28 13:31:32.780363596 UTC
    <6>[14201.872498] PM: Syncing filesystems ... done.
    

    中括号里的 [14201.684016] 代表内核开始启动后的时间,单位为秒。

    通过内核日志我们可以做一些事情,比如衡量内核启动时间,在系统启动完毕后的内核日志里找到 Freeing init memory 那一行前面的时间就是。

    查看设备信息

    型号

    命令:

    adb shell getprop ro.product.model
    

    输出示例:

    Nexus 5

    电池状况

    命令:

    adb shell dumpsys battery
    

    输入示例:

      Current Battery Service state:
      AC powered: false
      USB powered: true
      Wireless powered: false
      status: 2
      health: 2
      present: true
      level: 44
      scale: 100
      voltage: 3872
      temperature: 280
      technology: Li-poly
    

    其中 scale 代表最大电量,level 代表当前电量。上面的输出表示还剩下 44% 的电量。

    屏幕分辨率

    命令:

    adb shell wm size
    

    输出示例:

    Physical size: 1080x1920
    

    该设备屏幕分辨率为 1080px * 1920px。

    如果使用命令修改过,那输出可能是:

    Physical size: 1080x1920
    Override size: 480x1024
    

    表明设备的屏幕分辨率原本是 1080px * 1920px,当前被修改为 480px * 1024px。

    屏幕密度

    命令:

    adb shell wm density
    输出示例:

    Physical density: 420
    该设备屏幕密度为 420dpi。

    如果使用命令修改过,那输出可能是:

    Physical density: 480
    Override density: 160
    表明设备的屏幕密度原来是 480dpi,当前被修改为 160dpi。

    显示屏参数

    命令:

    adb shell dumpsys window displays
    

    输出示例:

    WINDOW MANAGER DISPLAY CONTENTS (dumpsys window displays)
      Display: mDisplayId=0
        init=1080x1920 420dpi cur=1080x1920 app=1080x1794 rng=1080x1017-1810x1731
        deferred=false layoutNeeded=false
    

    其中 mDisplayId 为 显示屏编号,init 是初始分辨率和屏幕密度,app 的高度比 init 里的要小,表示屏幕底部有虚拟按键,高度为 1920 - 1794 = 126px 合 42dp。

    android_id

    命令:

    adb shell settings get secure android_id
    

    输出示例:

    51b6be48bac8c569
    

    IMEI

    在 Android 4.4 及以下版本可通过如下命令获取 IMEI:

    adb shell dumpsys iphonesubinfo
    

    输出示例:

    Phone Subscriber Info:
      Phone Type = GSM
      Device ID = 860955027785041
    其中的 Device ID 就是 IMEI。
    

    而在 Android 5.0 及以上版本里这个命令输出为空,得通过其它方式获取了(需要 root 权限):

    adb shell
    su
    service call iphonesubinfo 1
    

    输出示例:

    Result: Parcel(
      0x00000000: 00000000 0000000f 00360038 00390030 '........8.6.0.9.'
      0x00000010: 00350035 00320030 00370037 00350038 '5.5.0.2.7.7.8.5.'
      0x00000020: 00340030 00000031                   '0.4.1...        ')
    

    把里面的有效内容提取出来就是 IMEI 了,比如这里的是 860955027785041。

    参考:adb shell dumpsys iphonesubinfo not working since Android 5.0 Lollipop

    Android 系统版本

    命令:

    adb shell getprop ro.build.version.release
    

    输出示例:

    5.0.2

    IP 地址

    每次想知道设备的 IP 地址的时候都得「设置」-「关于手机」-「状态信息」-「IP地址」很烦对不对?通过 adb 可以方便地查看。

    命令:

    adb shell ifconfig "| grep Mask"
    

    输出示例:

    inet addr:10.130.245.230  Mask:255.255.255.252
    inet addr:127.0.0.1  Mask:255.0.0.0
    

    那么 10.130.245.230 就是设备 IP 地址。

    在有的设备上这个命令没有输出,如果设备连着 WiFi,可以使用如下命令来查看局域网 adb shell ifconfig wlan0例:

    wlan0: ip 10.129.160.99 mask 255.255.240.0 flags [up broadcast running multicast]
    

    wlan0     Link encap:UNSPEC
              inet addr:10.129.168.57  Bcast:10.129.175.255  Mask:255.255.240.0
              inet6 addr: fe80::66cc:2eff:fe68:b6b6/64 Scope: Link
              UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
              RX packets:496520 errors:0 dropped:0 overruns:0 frame:0
              TX packets:68215 errors:0 dropped:0 overruns:0 carrier:0
              collisions:0 txqueuelen:3000
              RX bytes:116266821 TX bytes:8311736
    

    如果以上命令仍然不能得到期望的信息,那可以试试以下命令(部分系统版本里可用):

    adb shell netcfg
    

    输出示例:

    wlan0    UP                               10.129.160.99/20  0x00001043 f8:a9:d0:17:42:4d
    lo       UP                                   127.0.0.1/8   0x00000049 00:00:00:00:00:00
    p2p0     UP                                     0.0.0.0/0   0x00001003 fa:a9:d0:17:42:4d
    sit0     DOWN                                   0.0.0.0/0   0x00000080 00:00:00:00:00:00
    rmnet0   DOWN                                   0.0.0.0/0   0x00000000 00:00:00:00:00:00
    rmnet1   DOWN                                   0.0.0.0/0   0x00000000 00:00:00:00:00:00
    rmnet3   DOWN                                   0.0.0.0/0   0x00000000 00:00:00:00:00:00
    rmnet2   DOWN                                   0.0.0.0/0   0x00000000 00:00:00:00:00:00
    rmnet4   DOWN                                   0.0.0.0/0   0x00000000 00:00:00:00:00:00
    rmnet6   DOWN                                   0.0.0.0/0   0x00000000 00:00:00:00:00:00
    rmnet5   DOWN                                   0.0.0.0/0   0x00000000 00:00:00:00:00:00
    rmnet7   DOWN                                   0.0.0.0/0   0x00000000 00:00:00:00:00:00
    rev_rmnet3 DOWN                                   0.0.0.0/0   0x00001002 4e:b7:e4:2e:17:58
    rev_rmnet2 DOWN                                   0.0.0.0/0   0x00001002 4e:f0:c8:bf:7a:cf
    rev_rmnet4 DOWN                                   0.0.0.0/0   0x00001002 a6:c0:3b:6b:c4:1f
    rev_rmnet6 DOWN                                   0.0.0.0/0   0x00001002 66:bb:5d:64:2e:e9
    rev_rmnet5 DOWN                                   0.0.0.0/0   0x00001002 0e:1b:eb:b9:23:a0
    rev_rmnet7 DOWN                                   0.0.0.0/0   0x00001002 7a:d9:f6:81:40:5a
    rev_rmnet8 DOWN                                   0.0.0.0/0   0x00001002 4e:e2:a9:bb:d0:1b
    rev_rmnet0 DOWN                                   0.0.0.0/0   0x00001002 fe:65:d0:ca:82:a9
    rev_rmnet1 DOWN                                   0.0.0.0/0   0x00001002 da:d8:e8:4f:2e:fe
    

    可以看到网络连接名称、启用状态、IP 地址和 Mac 地址等信息。

    Mac 地址

    命令:

    adb shell cat /sys/class/net/wlan0/address
    

    输出示例:

    f8:a9:d0:17:42:4d
    

    这查看的是局域网 Mac 地址,移动网络或其它连接的信息可以通过前面的小节「IP 地址」里提到的 adb shell netcfg 命令来查看。

    CPU 信息

    命令:

    adb shell cat /proc/cpuinfo
    

    输出示例:

    Processor       : ARMv7 Processor rev 0 (v7l)
    processor       : 0
    BogoMIPS        : 38.40
    
    processor       : 1
    BogoMIPS        : 38.40
    
    processor       : 2
    BogoMIPS        : 38.40
    
    processor       : 3
    BogoMIPS        : 38.40
    
    Features        : swp half thumb fastmult vfp edsp neon vfpv3 tls vfpv4 idiva idivt
    CPU implementer : 0x51
    CPU architecture: 7
    CPU variant     : 0x2
    CPU part        : 0x06f
    CPU revision    : 0
    
    Hardware        : Qualcomm MSM 8974 HAMMERHEAD (Flattened Device Tree)
    Revision        : 000b
    Serial          : 0000000000000000
    

    这是 Nexus 5 的 CPU 信息,我们从输出里可以看到使用的硬件是 Qualcomm MSM 8974,processor 的编号是 0 到 3,所以它是四核的,采用的架构是 ARMv7 Processor rev 0 (v71)。

    内存信息

    命令:

    adb shell cat /proc/meminfo
    

    输出示例:

    MemTotal:        1027424 kB
    MemFree:          486564 kB
    Buffers:           15224 kB
    Cached:            72464 kB
    SwapCached:        24152 kB
    Active:           110572 kB
    Inactive:         259060 kB
    Active(anon):      79176 kB
    Inactive(anon):   207736 kB
    Active(file):      31396 kB
    Inactive(file):    51324 kB
    Unevictable:        3948 kB
    Mlocked:               0 kB
    HighTotal:        409600 kB
    HighFree:         132612 kB
    LowTotal:         617824 kB
    LowFree:          353952 kB
    SwapTotal:        262140 kB
    SwapFree:         207572 kB
    Dirty:                 0 kB
    Writeback:             0 kB
    AnonPages:        265324 kB
    Mapped:            47072 kB
    Shmem:              1020 kB
    Slab:              57372 kB
    SReclaimable:       7692 kB
    SUnreclaim:        49680 kB
    KernelStack:        4512 kB
    PageTables:         5912 kB
    NFS_Unstable:          0 kB
    Bounce:                0 kB
    WritebackTmp:          0 kB
    CommitLimit:      775852 kB
    Committed_AS:   13520632 kB
    VmallocTotal:     385024 kB
    VmallocUsed:       61004 kB
    VmallocChunk:     209668 kB
    

    其中,MemTotal 就是设备的总内存,MemFree 是当前空闲内存。

    更多硬件与系统属性

    设备的更多硬件与系统属性可以通过如下命令查看:

    adb shell cat /system/build.prop
    

    这会输出很多信息,包括前面几个小节提到的「型号」和「Android 系统版本」等。

    输出里还包括一些其它有用的信息,它们也可通过 adb shell getprop <属性名> 命令单独查看,列举一部分属性如下:

    属性名含义
    ro.build.version.sdkSDK 版本
    ro.build.version.releaseAndroid 系统版本
    ro.build.version.security_patchAndroid 安全补丁程序级别
    ro.product.model型号
    ro.product.brand品牌
    ro.product.name设备名
    ro.product.board处理器型号
    ro.product.cpu.abilistCPU 支持的 abi 列表[节注一]
    persist.sys.isUsbOtgEnabled是否支持 OTG
    dalvik.vm.heapsize每个应用程序的内存上限
    ro.sf.lcd_density屏幕密度

    节注一:

    一些小厂定制的 ROM 可能修改过 CPU 支持的 abi 列表的属性名,如果用 ro.product.cpu.abilist 属性名查找不到,可以这样试试:

    adb shell cat /system/build.prop | grep ro.product.cpu.abi
    

    示例输出:

    ro.product.cpu.abi=armeabi-v7a
    ro.product.cpu.abi2=armeabi
    

    修改设置

    注: 修改设置之后,运行恢复命令有可能显示仍然不太正常,可以运行 adb reboot 重启设备,或手动重启。

    修改设置的原理主要是通过 settings 命令修改 /data/data/com.android.providers.settings/databases/settings.db 里存放的设置值。

    分辨率

    命令:

    adb shell wm size 480x1024
    

    表示将分辨率修改为 480px * 1024px。

    恢复原分辨率命令:

    adb shell wm size reset
    

    屏幕密度

    命令:

    adb shell wm density 160
    

    表示将屏幕密度修改为 160dpi。

    恢复原屏幕密度命令:

    adb shell wm density reset
    

    显示区域

    命令:

    adb shell wm overscan 0,0,0,200
    

    四个数字分别表示距离左、上、右、下边缘的留白像素,以上命令表示将屏幕底部 200px 留白。

    恢复原显示区域命令:

    adb shell wm overscan reset
    

    关闭 USB 调试模式

    命令:

    adb shell settings put global adb_enabled 0
    恢复:

    用命令恢复不了了,毕竟关闭了 USB 调试 adb 就连接不上 Android 设备了。

    去设备上手动恢复吧:「设置」-「开发者选项」-「Android 调试」。

    状态栏和导航栏的显示隐藏

    本节所说的相关设置对应 Cyanogenmod 里的「扩展桌面」。

    命令:

    adb shell settings put global policy_control <key-values>
    

    <key-values> 可由如下几种键及其对应的值组成,格式为 <key1>=<value1>:<key2>=<value2>

    key含义
    immersive.full同时隐藏
    immersive.status隐藏状态栏
    immersive.navigation隐藏导航栏
    immersive.preconfirms?

    这些键对应的值可则如下值用逗号组合:

    value含义
    apps所有应用
    *所有界面
    packagename指定应用
    -packagename排除指定应用

    例如:

    adb shell settings put global policy_control immersive.full=*
    

    表示设置在所有界面下都同时隐藏状态栏和导航栏。

    adb shell settings put global policy_control immersive.status=com.package1,com.package2:immersive.navigation=apps,-com.package3
    

    表示设置在包名为 com.package1 和 com.package2 的应用里隐藏状态栏,在除了包名为 com.package3 的所有应用里隐藏导航栏。

    恢复正常模式

    不想全屏了咋办呢?

    adb shell settings put global policy_control null
    

    实用功能

    屏幕截图

    截图保存到电脑:

    adb exec-out screencap -p > sc.png
    

    如果 adb 版本较老,无法使用 exec-out 命令,这时候建议更新 adb 版本。无法更新的话可以使用以下麻烦点的办法:

    先截图保存到设备里:

    adb shell screencap -p /sdcard/sc.png
    

    然后将 png 文件导出到电脑:

    adb pull /sdcard/sc.png
    

    可以使用 adb shell screencap -h 查看 screencap 命令的帮助信息,下面是两个有意义的参数及含义:

    参数含义
    -p指定保存文件为 png 格式
    -d display-id指定截图的显示屏编号(有多显示屏的情况下)

    实测如果指定文件名以 .png 结尾时可以省略 -p 参数;否则需要使用 -p 参数。如果不指定文件名,截图文件的内容将直接输出到 stdout。

    另外一种一行命令截图并保存到电脑的方法:

    Linux 和 Windows

    adb shell screencap -p | sed "s/\r$//" > sc.png
    

    Mac OS X

    adb shell screencap -p | gsed "s/\r$//" > sc.png
    

    这个方法需要用到 gnu sed 命令,在 Linux 下直接就有,在 Windows 下 Git 安装目录的 bin 文件夹下也有。如果确实找不到该命令,可以下载 sed for Windows 并将 sed.exe 所在文件夹添加到 PATH 环境变量里。

    而在 Mac 下使用系统自带的 sed 命令会报错:

    sed: RE error: illegal byte sequence
    

    需要安装 gnu-sed,然后使用 gsed 命令:

    brew install gnu-sed
    

    录制屏幕

    录制屏幕以 mp4 格式保存到 /sdcard:

    adb shell screenrecord /sdcard/filename.mp4
    

    需要停止时按 Ctrl-C,默认录制时间和最长录制时间都是 180 秒。

    如果需要导出到电脑:

    adb pull /sdcard/filename.mp4
    

    可以使用 adb shell screenrecord --help 查看 screenrecord 命令的帮助信息,下面是常见参数及含义:

    参数含义
    --size WIDTHxHEIGHT视频的尺寸,比如 1280x720,默认是屏幕分辨率。
    --bit-rate RATE视频的比特率,默认是 4Mbps。
    --time-limit TIME录制时长,单位秒。
    --verbose输出更多信息。

    重新挂载 system 分区为可写

    注:需要 root 权限。

    /system 分区默认挂载为只读,但有些操作比如给 Android 系统添加命令、删除自带应用等需要对 /system 进行写操作,所以需要重新挂载它为可读写。

    步骤:

    进入 shell 并切换到 root 用户权限。

    命令:

    adb shell
    su
    

    查看当前分区挂载情况。

    命令:

    mount
    

    输出示例:

    rootfs / rootfs ro,relatime 0 0
    tmpfs /dev tmpfs rw,seclabel,nosuid,relatime,mode=755 0 0
    devpts /dev/pts devpts rw,seclabel,relatime,mode=600 0 0
    proc /proc proc rw,relatime 0 0
    sysfs /sys sysfs rw,seclabel,relatime 0 0
    selinuxfs /sys/fs/selinux selinuxfs rw,relatime 0 0
    debugfs /sys/kernel/debug debugfs rw,relatime 0 0
    none /var tmpfs rw,seclabel,relatime,mode=770,gid=1000 0 0
    none /acct cgroup rw,relatime,cpuacct 0 0
    none /sys/fs/cgroup tmpfs rw,seclabel,relatime,mode=750,gid=1000 0 0
    none /sys/fs/cgroup/memory cgroup rw,relatime,memory 0 0
    tmpfs /mnt/asec tmpfs rw,seclabel,relatime,mode=755,gid=1000 0 0
    tmpfs /mnt/obb tmpfs rw,seclabel,relatime,mode=755,gid=1000 0 0
    none /dev/memcg cgroup rw,relatime,memory 0 0
    none /dev/cpuctl cgroup rw,relatime,cpu 0 0
    none /sys/fs/cgroup tmpfs rw,seclabel,relatime,mode=750,gid=1000 0 0
    none /sys/fs/cgroup/memory cgroup rw,relatime,memory 0 0
    none /sys/fs/cgroup/freezer cgroup rw,relatime,freezer 0 0
    /dev/block/platform/msm_sdcc.1/by-name/system /system ext4 ro,seclabel,relatime,data=ordered 0 0
    /dev/block/platform/msm_sdcc.1/by-name/userdata /data ext4 rw,seclabel,nosuid,nodev,relatime,noauto_da_alloc,data=ordered 0 0
    /dev/block/platform/msm_sdcc.1/by-name/cache /cache ext4 rw,seclabel,nosuid,nodev,relatime,data=ordered 0 0
    /dev/block/platform/msm_sdcc.1/by-name/persist /persist ext4 rw,seclabel,nosuid,nodev,relatime,data=ordered 0 0
    /dev/block/platform/msm_sdcc.1/by-name/modem /firmware vfat ro,context=u:object_r:firmware_file:s0,relatime,uid=1000,gid=1000,fmask=0337,dmask=0227,codepage=cp437,iocharset=iso8859-1,shortname=lower,errors=remount-ro 0 0
    /dev/fuse /mnt/shell/emulated fuse rw,nosuid,nodev,relatime,user_id=1023,group_id=1023,default_permissions,allow_other 0 0
    /dev/fuse /mnt/shell/emulated/0 fuse rw,nosuid,nodev,relatime,user_id=1023,group_id=1023,default_permissions,allow_other 0 0
    

    找到其中我们关注的带 /system 的那一行:

    /dev/block/platform/msm_sdcc.1/by-name/system /system ext4 ro,seclabel,relatime,data=ordered 0 0
    

    重新挂载。

    命令:

    mount -o remount,rw -t yaffs2 /dev/block/platform/msm_sdcc.1/by-name/system /system
    

    这里的 /dev/block/platform/msm_sdcc.1/by-name/system 就是我们从上一步的输出里得到的文件路径。

    如果输出没有提示错误的话,操作就成功了,可以对 /system 下的文件为所欲为了。

    查看连接过的 WiFi 密码

    注:需要 root 权限。

    命令:

    adb shell
    su
    cat /data/misc/wifi/*.conf
    

    输出示例:

    network={
    	ssid="TP-LINK_9DFC"
    	scan_ssid=1
    	psk="123456789"
    	key_mgmt=WPA-PSK
    	group=CCMP TKIP
    	auth_alg=OPEN
    	sim_num=1
    	priority=13893
    }
    
    network={
    	ssid="TP-LINK_F11E"
    	psk="987654321"
    	key_mgmt=WPA-PSK
    	sim_num=1
    	priority=17293
    }
    

    ssid 即为我们在 WLAN 设置里看到的名称,psk 为密码,key_mgmt 为安全加密方式。

    设置系统日期和时间

    注:需要 root 权限。

    命令:

    adb shell
    su
    date -s 20160823.131500
    

    表示将系统日期和时间更改为 2016 年 08 月 23 日 13 点 15 分 00 秒。

    重启手机

    命令:

    adb reboot
    

    检测设备是否已 root

    命令:

    adb shell
    su
    

    此时命令行提示符是 $ 则表示没有 root 权限,是 # 则表示已 root。

    使用 Monkey 进行压力测试

    Monkey 可以生成伪随机用户事件来模拟单击、触摸、手势等操作,可以对正在开发中的程序进行随机压力测试。

    简单用法:

    adb shell monkey -p <packagename> -v 500
    

    表示向 <packagename> 指定的应用程序发送 500 个伪随机事件。

    Monkey 的详细用法参考 官方文档。

    开启/关闭 WiFi

    注:需要 root 权限。

    有时需要控制设备的 WiFi 状态,可以用以下指令完成。

    开启 WiFi:

    adb root
    adb shell svc wifi enable
    

    关闭 WiFi:

    adb root
    adb shell svc wifi disable
    

    设置wifi优先,有网络和wifi情况下优先使用wifi

    adb shell svc wifi prefer 
    

    若执行成功,输出为空;若未取得 root 权限执行此命令,将执行失败,输出 Killed。

    开启/关闭 数据流量

    svc data disable
    

    这个命令可以关闭数据连接,就是上网流量,大家都知道控制上网的开关很多, 但是大都是通过在apn上的接入点加后缀来实现的,但是这个命令不会更改apn的任何设置,直接在底层关闭数据连接。 应该是最彻底的,而且又不影响apn的设置。这个跟apndroid有什么区别,apndroid是在关闭上网数据的时候,已经在下载的连接可能不会被强 制关闭(这个在apndroid自己的说明中也有提到)。比如你在下载一个10M的电影,下载了1M,不响下载了。用apndroid关闭连接,可能这个 下载还会继续,不会马上停掉。但是用这个命令,绝对毫不留情的咔嚓掉。

    adb shell svc data enable 
    

    这个是打开上网数据连接,跟上一个命令是相反的。

    adb shell svc data prefer
    

    这个命令是控制数据连接比wifi优先。我们都知道,正常情况下,有wifi的时候,不会用到数据网络连接。但是这个命令是相反,有数据网络的话先用数据网络流量,没有数据网络的时候采用wifi .

    刷机相关命令

    重启到 Recovery 模式

    命令:

    adb reboot recovery
    

    从 Recovery 重启到 Android

    命令:

    adb reboot
    

    重启到 Fastboot 模式

    命令:

    adb reboot bootloader
    

    通过 sideload 更新系统

    如果我们下载了 Android 设备对应的系统更新包到电脑上,那么也可以通过 adb 来完成更新。

    以 Recovery 模式下更新为例:

    重启到 Recovery 模式。

    命令:

    adb reboot recovery
    

    在设备的 Recovery 界面上操作进入 Apply update-Apply from ADB。

    注:不同的 Recovery 菜单可能与此有差异,有的是一级菜单就有 Apply update from ADB。

    通过 adb 上传和更新系统。

    命令:

    adb sideload <path-to-update.zip>
    

    更多 adb shell 命令

    Android 系统是基于 Linux 内核的,所以 Linux 里的很多命令在 Android 里也有相同或类似的实现,在 adb shell 里可以调用。本文档前面的部分内容已经用到了 adb shell 命令。

    查看进程

    adb shell ps
    

    例:

    USER     PID   PPID  VSIZE  RSS     WCHAN    PC        NAME
    root      1     0     8904   788   ffffffff 00000000 S /init
    root      2     0     0      0     ffffffff 00000000 S kthreadd
    ...
    u0_a71    7779  5926  1538748 48896 ffffffff 00000000 S com.sohu.inputmethod.sogou:classic
    u0_a58    7963  5926  1561916 59568 ffffffff 00000000 S org.mazhuang.boottimemeasure
    ...
    shell     8750  217   10640  740   00000000 b6f28340 R ps
    

    各列含义:

    列名含义
    USER所属用户
    PID进程 ID
    PPID父进程 ID
    NAME进程名

    查看实时资源占用情况

    adb shell top
    

    例:

    User 0%, System 6%, IOW 0%, IRQ 0%
    User 3 + Nice 0 + Sys 21 + Idle 280 + IOW 0 + IRQ 0 + SIRQ 3 = 307
    
      PID PR CPU% S  #THR     VSS     RSS PCY UID      Name
     8763  0   3% R     1  10640K   1064K  fg shell    top
      131  0   3% S     1      0K      0K  fg root     dhd_dpc
     6144  0   0% S   115 1682004K 115916K  fg system   system_server
      132  0   0% S     1      0K      0K  fg root     dhd_rxf
     1731  0   0% S     6  20288K    788K  fg root     /system/bin/mpdecision
      217  0   0% S     6  18008K    356K  fg shell    /sbin/adbd
     ...
     7779  2   0% S    19 1538748K  48896K  bg u0_a71   com.sohu.inputmethod.sogou:classic
     7963  0   0% S    18 1561916K  59568K  fg u0_a58   org.mazhuang.boottimemeasure
     ...
    

    各列含义:

    列名含义
    PID进程 ID
    PR优先级
    CPU%当前瞬间占用 CPU 百分比
    S进程状态(R=运行,S=睡眠,T=跟踪/停止,Z=僵尸进程)
    #THR线程数
    VSSVirtual Set Size 虚拟耗用内存(包含共享库占用的内存)
    RSSResident Set Size 实际使用物理内存(包含共享库占用的内存)
    PCY调度策略优先级,SP_BACKGROUND/SPFOREGROUND
    UID进程所有者的用户 ID
    NAME进程名

    top 命令还支持一些命令行参数,详细用法如下:

    Usage: top [ -m max_procs ] [ -n iterations ] [ -d delay ] [ -s sort_column ] [ -t ] [ -h ]
        -m num  最多显示多少个进程
        -n num  刷新多少次后退出
        -d num  刷新时间间隔(单位秒,默认值 5)
        -s col  按某列排序(可用 col 值:cpu, vss, rss, thr)
        -t      显示线程信息
        -h      显示帮助文档
    

    查看进程 UID

    有两种方案:

    adb shell dumpsys package <packagename> | grep userId=
    

    如:

    $ adb shell dumpsys package org.mazhuang.guanggoo | grep userId=
       userId=10394
    

    通过 ps 命令找到对应进程的 pid 之后 adb shell cat /proc/<pid>/status | grep Uid

    如:

    $ adb shell
    gemini:/ $ ps | grep org.mazhuang.guanggoo
    u0_a394   28635 770   1795812 78736 SyS_epoll_ 0000000000 S org.mazhuang.guanggoo
    gemini:/ $ cat /proc/28635/status | grep Uid
    Uid:    10394   10394   10394   10394
    gemini:/ $
    

    其它

    如下是其它常用命令的简单描述,前文已经专门讲过的命令不再额外说明:

    命令功能
    cat显示文件内容
    cd切换目录
    chmod改变文件的存取模式/访问权限
    df查看磁盘空间使用情况
    grep过滤输出
    kill杀死指定 PID 的进程
    ls列举目录内容
    mount挂载目录的查看和管理
    mv移动或重命名文件
    ps查看正在运行的进程
    rm删除文件
    top查看进程的资源占用情况

    安全相关

    启用 SELinux

    启用 SELinux

    adb root
    adb shell setenforce 1
    

    禁用 SELinux

    adb root
    adb shell setenforce 0
    

    启用 dm_verity

    adb root
    adb enable-verity
    

    禁用 dm_verity

    adb root
    adb disable-verity
    

    常见问题

    启动 adb server 失败

    出错提示

    error: protocol fault (couldn't read status): No error
    

    可能原因

    adb server 进程想使用的 5037 端口被占用。

    解决方案

    找到占用 5037 端口的进程,然后终止它。以 Windows 下为例:

    netstat -ano | findstr LISTENING
    
    ...
    TCP    0.0.0.0:5037           0.0.0.0:0              LISTENING       1548
    ...
    

    这里 1548 即为进程 ID,用命令结束该进程:

    taskkill /PID 1548
    

    然后再启动 adb 就没问题了。

    展开全文
  • HBase Shell命令大全

    万次阅读 多人点赞 2019-03-18 20:55:18
    HBase关键名称: ...如果配置了HBase的环境变量了,就可以知己在命令行中输入hbase shell 命令进入命令行。 hbase shell help命令 可以通过 help '命名名称'来查看命令行的具体使用 查询服务器状态st...

    一:简介

    HBase的名字的来源于Hadoop database,即hadoop数据库,不同于一般的关系数据库,它是非结构化数据存储的数据库,而且它是基于列的而不是基于行的模式。

    HBase是一个分布式的、面向列的、基于Google Bigtable的开源实现。
    利用Hadoop HDFS作为其文件存储系统,
    利用Hadoop MapReduce来处理HBase中的海量数据,
    利用Zookeeper作为协同服务。

    二:HBase重要概念

    HBase的表结构

    HBase以表的形式存储数据。表有行和列组成。列划分为若干个列族/列簇(column family),每个列族/列簇下面可以有多个普通列。

    在这里插入图片描述

    表Table

    HBase是用表来存储数据的。

    命名空间namespace

    namespace命名空间指对一组表的逻辑分组,类似RDBMS中的database,方便对表在业务上划分。
    HBase系统默认定义了两个缺省的namespace:

    • hbase:系统内建表,包含namespace和meta表
    • default:用户建表时未指定namespace的表都创建在此

    行键 Row Key

    行键,每一行的主键列,每行的行键要唯一,行键的值为任意字符串(最大长度是 64KB,实际应用中长度一般为 10-100bytes),在HBase内部,rowKey保存为字节数组byte[]
    行的一次读写是原子操作 (不论一次读写多少列)

    区域Region

    Table在行的方向上分割为多个Region。

    Region是按大小分割的,每个表开始只有一个region,随着数据的增多,region不断增大,当增大到一个阀值的时候,region就会等分为两个新的region,之后会有越来越多的region。

    Region是HBase中分布式存储和负载均衡的最小单元。不同的Region分布到不同的RegionServer上。

    Region由一个或者多个Store组成, 每个Store保存一个column family, 每个Store又由一个MemStore(存储在内存中)和0到多个StoreFile(存储在HDFS上)组成
    在这里插入图片描述

    列族 column family

    列族是每个子列的父级,每个子列都属于一个列族,一个列族包含一个或者多个相关列,创建表的时候需要指定列族,而列不需要必须指定。通过“列族名:列名”来表示某个具体的子列。

    HBase中的Schema就是 TableName + Column Family Name

    列限定符

    就是列族下的每个子列名称,或者称为相关列,或者称为限定符,只是翻译不同。
    通过columnFamily:column来定位某个子列。

    存储单元 cell

    我们外观看到的每个单元格其实都对应着多个存储单元,默认情况下一个单元格对应着一个存储单元,一个存储单元可以存储一份数据,如果一个单元格有多个存储单元就表示一个单元格可以存储多个值。可以通过version来设置存储单元个数。可以通过
    rowKey + columnFamily + column + timestamp来唯一确定一个存储单元。cell中的数据是没有类型的,全部是字节码形式存贮。

    hbase按照时间戳降序排列各时间版本,其他映射建按照升序排序。

    时间戳版本号 timestamp

    每个cell都保存着同一份数据的多个版本。版本通过时间戳来索引。时间戳的类型是 64位整型。时间戳可以由hbase(在数据写入时自动 )赋值,此时时间戳是精确到毫秒的当前系统时间。时间戳也可以由客户显式赋值。如果应用程序要避免数据版本冲突,就必须自己生成具有唯一性的时间戳。每个cell中,不同版本的数据按照时间倒序排序,即最新的数据排在最前面。

    为了避免数据存在过多版本造成的的管理 (包括存贮和索引)负担,hbase提供了两种数据版本回收方式。一是保存数据的最后n个版本,二是保存最近一段时间内的版本(比如最近七天)。用户可以针对每个列族进行设置。

    三:HBase Shell

    命名描述语法
    help ‘命名名’查看命令的使用描述help ‘命令名’
    whoami我是谁whoami
    version返回hbase版本信息version
    status返回hbase集群的状态信息status
    table_help查看如何操作表table_help
    create创建表create ‘表名’, ‘列族名1’, ‘列族名2’, ‘列族名N’
    alter修改列族添加一个列族:alter ‘表名’, ‘列族名’
    删除列族:alter ‘表名’, {NAME=> ‘列族名’, METHOD=> ‘delete’}
    describe显示表相关的详细信息describe ‘表名’
    list列出hbase中存在的所有表list
    exists测试表是否存在exists ‘表名’
    put添加或修改的表的值put ‘表名’, ‘行键’, ‘列族名’, ‘列值’
    put ‘表名’, ‘行键’, ‘列族名:列名’, ‘列值’
    scan通过对表的扫描来获取对用的值scan ‘表名’
    扫描某个列族: scan ‘表名’, {COLUMN=>‘列族名’}
    扫描某个列族的某个列: scan ‘表名’, {COLUMN=>‘列族名:列名’}
    查询同一个列族的多个列: scan ‘表名’, {COLUMNS => [ ‘列族名1:列名1’, ‘列族名1:列名2’, …]}
    get获取行或单元(cell)的值get ‘表名’, ‘行键’
    get ‘表名’, ‘行键’, ‘列族名’
    count统计表中行的数量count ‘表名’
    incr增加指定表行或列的值incr ‘表名’, ‘行键’, ‘列族:列名’, 步长值
    get_counter获取计数器get_counter ‘表名’, ‘行键’, ‘列族:列名’
    delete删除指定对象的值(可以为表,行,列对应的值,另外也可以指定时间戳的值)删除列族的某个列: delete ‘表名’, ‘行键’, ‘列族名:列名’
    deleteall删除指定行的所有元素值deleteall ‘表名’, ‘行键’
    truncate重新创建指定表truncate ‘表名’
    enable使表有效enable ‘表名’
    is_enabled是否启用is_enabled ‘表名’
    disable使表无效disable ‘表名’
    is_disabled是否无效is_disabled ‘表名’
    drop删除表drop的表必须是disable的
    disable ‘表名’
    drop ‘表名’
    shutdown关闭hbase集群(与exit不同)
    tools列出hbase所支持的工具
    exit退出hbase shell

    HBase Shell 是官方提供的一组命令,用于操作HBase。如果配置了HBase的环境变量了,就可以知己在命令行中输入hbase shell 命令进入命令行。

    hbase shell
    

    在这里插入图片描述

    help命令

    可以通过 help '命名名称'来查看命令行的具体使用,包括命令的作用和用法。
    通过help ‘hbase’ 命名来查看hbase shell 支持的所有命令,hbase将命令进行分组,其中ddl、dml使用较多。
    在这里插入图片描述

    在这里插入图片描述

    四:general 命名

    1. 显示集群状态status

    可以为 ‘summary’, ‘simple’, ‘detailed’, or ‘replication’. 默认为 ‘summary’

    hbase> status
    hbase> status 'simple'
    hbase> status 'summary'
    hbase> status 'detailed'
    hbase> status 'replication'
    hbase> status 'replication', 'source'
    hbase> status 'replication', 'sink'
    

    在这里插入图片描述

    2. 查询数据库版本version

    在这里插入图片描述

    3. 显示当前用户与组 whoami

    在这里插入图片描述

    4. 查看操作表的命令table_help

    在这里插入图片描述

    5. 退出HBase Shell exit

    exit
    

    五:ddl命令

    1. 创建表create

    注意:创建表时只需要指定列族名称,不需要指定列名。

    # 语法
    create '表名', {NAME => '列族名1'}, {NAME => '列族名2'}, {NAME => '列族名3'}
    # 此种方式是上上面的简写方式,使用上面方式可以为列族指定更多的属性,如VERSIONS、TTL、BLOCKCACHE、CONFIGURATION等属性
    create '表名', '列族名1', '列族名2', '列族名3'
    
    create '表名', {NAME => '列族名1', VERSIONS => 版本号, TTL => 过期时间, BLOCKCACHE => true}
    
    
    # 示例
    create 'tbl_user', 'info', 'detail'
    create 't1', {NAME => 'f1', VERSIONS => 1, TTL => 2592000, BLOCKCACHE => true}
    

    在这里插入图片描述

    2. 修改(添加、删除)表结构Schema alter

    2.1 添加一个列族

    # 语法 
    alter '表名', '列族名'
    
    # 示例
    alter 'tbl_user', 'address'
    

    在这里插入图片描述

    2.2 删除一个列族

    # 语法 
    alter '表名', {NAME=> '列族名', METHOD=> 'delete'}
    
    # 示例
    alter 'tbl_user', {NAME=> 'address', METHOD=> 'delete'}
    

    在这里插入图片描述
    3.3 修改列族的属性
    可以修改列族的VERSIONS、IN_MEMORY

    # 修改f1列族的版本为5
    alter 't1', NAME => 'f1', VERSIONS => 5
    
    # 修改多个列族,修改f2为内存,版本号为5
    alter 't1', 'f1', {NAME => 'f2', IN_MEMORY => true}, {NAME => 'f3', VERSIONS => 5}
    
    # 也可以修改table-scope属性,例如MAX_FILESIZE, READONLY,MEMSTORE_FLUSHSIZE, DEFERRED_LOG_FLUSH等。
    # 例如,修改region的最大大小为128MB:
    alter 't1', MAX_FILESIZE => '134217728'
    

    3. 异步修改Schema alter_async

    # change or add the 'f1' column family in table 't1' from defaults
    to instead keep a maximum of 5 cell VERSIONS
    alter_async 't1', NAME => 'f1', VERSIONS => 5
    
    # delete the 'f1' column family in table 'ns1:t1'
    alter_async 'ns1:t1', NAME => 'f1', METHOD => 'delete'
    alter_async 'ns1:t1', 'delete' => 'f1'
    
    # change the max size of a family to 128MB
    alter 't1', METHOD => 'table_att', MAX_FILESIZE => '134217728'
    alter 't1', {NAME => 'f1'}, {NAME => 'f2', METHOD => 'delete'}
    

    4. 获取alter_async执行的状态 alter_status

    alter_status '表名'
    

    5. 获取表的描述describe

    # 语法 
    describe '表名'
    
    # 示例
    describe 'tbl_user'
    

    在这里插入图片描述

    6. 列举所有表list

    在这里插入图片描述

    7. 表是否存在exists

    # 语法 
    exists '表名'
    
    # 示例
    exists 'tbl_user'
    

    在这里插入图片描述

    8. 启用表enable和禁用表disable

    通过enable和disable来启用/禁用这个表,相应的可以通过is_enabled和is_disabled来检查表是否被禁用。

    # 语法
    enable '表名'
    is_enabled '表名'
    
    disable '表名'
    is_disabled '表名'
    
    # 示例
    disable 'tbl_user'
    is_disabled 'tbl_user'
    
    enable 'tbl_user'
    is_enabled 'tbl_user'
    

    在这里插入图片描述

    9. 禁用满足正则表达式的所有表disable_all

    • .匹配除“\n”和"\r"之外的任何单个字符
    • *匹配前面的子表达式任意次
    # 匹配以t开头的表名
    disable_all 't.*'
    # 匹配指定命名空间ns下的以t开头的所有表
    disable_all 'ns:t.*'
    # 匹配ns命名空间下的所有表
    disable_all 'ns:.*'
    

    10. 启用满足正则表达式的所有表enable_all

    enable_all 't.*'
    enable_all 'ns:t.*'
    enable_all 'ns:.*'
    

    11. 删除表drop

    需要先禁用表,然后再删除表,启用的表是不允许删除的

    # 语法
    disable '表名'
    drop '表名'
    
    # 示例
    disable 'tbl_user'
    drop 'tbl_user'
    

    在这里插入图片描述

    12. 删除满足正则表达式的所有表drop_all

    drop_all 't.*'
    drop_all 'ns:t.*'
    drop_all 'ns:.*'
    

    13. 获取某个表赋值给一个变量 get_table

    通过 var = get_table ‘表名’ 赋值给一个变量对象,然后对象.来调用,就像面向对象编程一样,通过对象.方法来调用,这种方式在操作某个表时就不必每次列举表名了。
    在这里插入图片描述

    14. 获取rowKey所在的区 locate_region

    locate_region '表名', '行键'
    

    在这里插入图片描述

    15. 显示hbase所支持的所有过滤器show_filters

    过滤器用于get和scan命令中作为筛选数据的条件,类型关系型数据库中的where的作用
    在这里插入图片描述


    六:namespace命令

    1. 列举命名空间 list_namespace

    在这里插入图片描述

    2. 获取命名空间描述 describe_namespace

    在这里插入图片描述

    3. 查看命名空间下的所有表 list_namespace_tables

    在这里插入图片描述

    4. 创建命名空间create_namespace

    在这里插入图片描述

    5. 修改命名空间的属性

    # add/modify a property
    alter_namespace 'ns1', {METHOD => 'set', 'PROPERTY_NAME' => 'PROPERTY_VALUE'}
    # delete a property
    alter_namespace 'ns1', {METHOD => 'unset', NAME=>'PROPERTY_NAME'}
    

    6. 删除命名空间drop_namespace

    drop_namespace '命名空间名称'
    

    七:dml命令

    1. 插入或者修改数据put

    # 语法
    # 当列族中只有一个列时'列族名:列名'使用'列族名'
    put '表名', '行键', '列族名', '列值'
    put '表名', '行键', '列族名:列名', '列值'
    
    # 示例
    
    # 创建表
    create 'tbl_user', 'info', 'detail', 'address'
    
    # 第一行数据
    put 'tbl_user', 'mengday', 'info:id', '1'
    put 'tbl_user', 'mengday', 'info:name', '张三'
    put 'tbl_user', 'mengday', 'info:age', '28'
    
    put 'tbl_user', 'mengday', 'detail:birthday', '1990-06-26'
    put 'tbl_user', 'mengday', 'detail:email', 'abc@163.com'
    put 'tbl_user', 'mengday', 'detail:create_time', '2019-03-04 14:26:10'
    
    put 'tbl_user', 'mengday', 'address', '上海市'
    
    # 第二行数据
    put 'tbl_user', 'vbirdbest', 'info:id', '2'
    put 'tbl_user', 'vbirdbest', 'info:name', '李四'
    put 'tbl_user', 'vbirdbest', 'info:age', '27'
    
    put 'tbl_user', 'vbirdbest', 'detail:birthday', '1990-06-27'
    put 'tbl_user', 'vbirdbest', 'detail:email', 'xxx@gmail.com'
    put 'tbl_user', 'vbirdbest', 'detail:create_time', '2019-03-05 14:26:10'
    
    put 'tbl_user', 'vbirdbest', 'address', '北京市'
    
    
    # 第一行数据
    put 'tbl_user', 'xiaoming', 'info:id', '3'
    put 'tbl_user', 'xiaoming', 'info:name', '王五'
    put 'tbl_user', 'xiaoming', 'info:age', '26'
    
    put 'tbl_user', 'xiaoming', 'detail:birthday', '1990-06-28'
    put 'tbl_user', 'xiaoming', 'detail:email', 'xyz@qq.com'
    put 'tbl_user', 'xiaoming', 'detail:create_time', '2019-03-06 14:26:10'
    
    put 'tbl_user', 'xiaoming', 'address', '杭州市'
    

    在这里插入图片描述

    2. 全表扫描scan

    获取表的所有数据

    # 语法
    scan '表名'
    
    # 示例
    scan 'tbl_user'
    

    在这里插入图片描述
    注意:中文编码了

    扫描整个列簇

    # 语法
    scan '表名', {COLUMN=>'列族名'}
    
    # 示例
    scan 'tbl_user', {COLUMN=>'info'}
    

    在这里插入图片描述

    扫描整个列簇的某个列

    # 语法
    scan '表名', {COLUMN=>'列族名:列名'}
    
    # 示例
    scan 'tbl_user', {COLUMN=>'info:age'}
    

    在这里插入图片描述

    3. 获取数据get

    # 语法
    get '表名', '行键'
    
    # 示例
    get 'tbl_user', 'mengday'
    

    在这里插入图片描述
    根据某一行某列族的数据

    # 语法
    get '表名', '行键', '列族名'
    
    # 示例
    get 'tbl_user', 'mengday', 'info'
    

    在这里插入图片描述

    # 创建表,c1版本为4, 元数据mykey=myvalue
    hbase(main):009:0> create 't1', {NAME => 'c1', VERSIONS => 4}, METADATA => { 'mykey' => 'myvalue' }
    0 row(s) in 2.2810 seconds
    
    => Hbase::Table - t1
    # 添加列族c2, c3
    hbase(main):010:0> alter 't1', 'c2', 'c3'
    Updating all regions with the new schema...
    1/1 regions updated.
    Done.
    Updating all regions with the new schema...
    1/1 regions updated.
    Done.
    0 row(s) in 3.8320 seconds
    
    # 出入数据,c1 插入4个版本的值
    hbase(main):011:0> put 't1', 'r1', 'c1', 'v1'
    0 row(s) in 0.1000 seconds
    
    hbase(main):012:0> put 't1', 'r1', 'c1', 'v11'
    0 row(s) in 0.0180 seconds
    
    hbase(main):013:0> put 't1', 'r1', 'c1', 'v111'
    0 row(s) in 0.0140 seconds
    
    hbase(main):014:0> put 't1', 'r1', 'c1', 'v1111'
    0 row(s) in 0.0140 seconds
    
    # 插入c2、c3的值
    hbase(main):015:0> put 't1', 'r1', 'c2', 'v2'
    0 row(s) in 0.0140 seconds
    
    hbase(main):016:0> put 't1', 'r1', 'c3', 'v3'
    0 row(s) in 0.0210 seconds
    
    # 获取rowKey=r1的一行记录
    hbase(main):017:0> get 't1', 'r1'
    COLUMN                                              CELL
     c1:                                                timestamp=1552819382575, value=v1111
     c2:                                                timestamp=1552819392398, value=v2
     c3:                                                timestamp=1552819398244, value=v3
    3 row(s) in 0.0550 seconds
    
    # 获取rowKey=r1并且 1552819392398 <= 时间戳范围 < 1552819398244
    hbase(main):018:0> get 't1', 'r1', {TIMERANGE => [1552819392398, 1552819398244]}
    COLUMN                                              CELL
     c2:                                                timestamp=1552819392398, value=v2
    1 row(s) in 0.0090 seconds
    
    # 获取指定列的值
    hbase(main):019:0> get 't1', 'r1', {COLUMN => 'c1'}
    COLUMN                                              CELL
     c1:                                                timestamp=1552819382575, value=v1111
    1 row(s) in 0.0160 seconds
    
    # 获取指定列的值,多个值使用数组表示
    hbase(main):020:0> get 't1', 'r1', {COLUMN => ['c1', 'c2', 'c3']}
    COLUMN                                              CELL
     c1:                                                timestamp=1552819382575, value=v1111
     c2:                                                timestamp=1552819392398, value=v2
     c3:                                                timestamp=1552819398244, value=v3
    3 row(s) in 0.0170 seconds
    
    # 获取c1的值,获取4个版本的值,默认是按照时间戳降续排序的
    hbase(main):021:0> get 't1', 'r1', {COLUMN => 'c1', VERSIONS => 4}
    COLUMN                                              CELL
     c1:                                                timestamp=1552819382575, value=v1111
     c1:                                                timestamp=1552819376343, value=v111
     c1:                                                timestamp=1552819368993, value=v11
     c1:                                                timestamp=1552819362975, value=v1
    4 row(s) in 0.0180 seconds
    
    # 获取c1的3个版本值
    hbase(main):027:0* get 't1', 'r1', {COLUMN => 'c1', VERSIONS => 3}
    COLUMN                                               CELL
     c1:                                                 timestamp=1552819382575, value=v1111
     c1:                                                 timestamp=1552819376343, value=v111
     c1:                                                 timestamp=1552819368993, value=v11
    3 row(s) in 0.0090 seconds
    
    # 获取指定时间戳版本的列
    hbase(main):022:0> get 't1', 'r1', {COLUMN => 'c1', TIMESTAMP => 1552819376343}
    COLUMN                                              CELL
     c1:                                                timestamp=1552819376343, value=v111
    1 row(s) in 0.0170 seconds
    
    hbase(main):023:0> get 't1', 'r1', {COLUMN => 'c1', TIMESTAMP => 1552819376343, VERSIONS => 4}
    COLUMN                                              CELL
     c1:                                                timestamp=1552819376343, value=v111
    1 row(s) in 0.0130 seconds
    
    # 获取rowKey=r1中的值等于v2的所有列
    hbase(main):024:0> get 't1', 'r1', {FILTER => "ValueFilter(=, 'binary:v2')"}
    COLUMN                                              CELL
     c2:                                                timestamp=1552819392398, value=v2
    1 row(s) in 0.0510 seconds
    
    
    hbase(main):025:0> get 't1', 'r1', {COLUMN => 'c1', ATTRIBUTES => {'mykey'=>'myvalue'}}
    COLUMN                                              CELL
     c1:                                                timestamp=1552819382575, value=v1111
    1 row(s) in 0.0100 seconds
    

    4. 删除某个列族中的某个列delete

    # 语法
    delete '表名', '行键', '列族名:列名'
    
    
    create 'tbl_test', 'columnFamily1'
    
    put 'tbl_test', 'rowKey1', 'columnFamily1:column1', 'value1'
    put 'tbl_test', 'rowKey1', 'columnFamily1:column2', 'value2'
    
    delete 'tbl_test', 'rowKey1', 'columnFamily1:column1'
    

    在这里插入图片描述

    5. 删除某行数据deleteall

    # 语法
    deleteall '表名', '行键'
    
    # 示例
    deleteall 'tbl_test', 'rowKey1'
    

    在这里插入图片描述

    6. 清空整个表的数据truncate

    先disable表,然后再drop表,最后重新create表

    truncate '表名'
    

    在这里插入图片描述

    7. 查询表中有多少行count

    # 语法
    count '表名'
    
    # 示例
    count 'tbl_user'
    

    在这里插入图片描述

    8. 自增incr

    # 语法
    incr '表名', '行键', '列族:列名', 步长值
    
    # 示例 
    # 注意:incr 可以对不存的行键操作,如果行键已经存在会报错,如果使用put修改了incr的值再使用incr也会报错
    # ERROR: org.apache.hadoop.hbase.DoNotRetryIOException: Field is not a long, it's 2 bytes wide
    incr 'tbl_user', 'xiaohong', 'info:age', 1
    

    在这里插入图片描述

    9. 计数器get_counter

    # 点击量:日、周、月
    create 'counters', 'daily', 'weekly', 'monthly'
    incr 'counters', '20110101', 'daily:hits', 1
    incr 'counters', '20110101', 'daily:hits', 1
    get_counter 'counters', '20110101', 'daily:hits'
    

    在这里插入图片描述

    10. 修饰词

    10.1 COLUMNS: 查询同一个列族的多个列
    # 语法
    
    scan '表名', {COLUMNS => [ '列族名1:列名1', '列族名1:列名2', ...]}
    
    # 示例
    scan 'tbl_user', {COLUMNS => [ 'info:id', 'info:age']}
    

    在这里插入图片描述

    10.2 TIMESTAMP 指定时间戳
    scan 't1', {COLUMNS => 'c2', TIMESTAMP=> 1552819392398}
    
    10.3 TIMERANGE表示的是”>=开始时间 and <结束时间“
    # 语法
    scan '表名',{TIMERANGE=>[timestamp1, timestamp2]}
    
    # 示例
    scan 'tbl_user',{TIMERANGE=>[1551938004321, 1551938036450]}
    

    在这里插入图片描述

    10.4 VERSIONS

    默认情况下一个列只能存储一个数据,后面如果修改数据就会将原来的覆盖掉,可以通过指定VERSIONS时HBase一列能存储多个值。

    create 'tbl_test', 'columnFamily1'
    describe 'tbl_test'
    
    # 修改列族版本号
    alter 'tbl_test', { NAME=>'columnFamily1', VERSIONS=>3 }
    
    put 'tbl_test', 'rowKey1', 'columnFamily1:column1', 'value1'
    put 'tbl_test', 'rowKey1', 'columnFamily1:column1', 'value2'
    put 'tbl_test', 'rowKey1', 'columnFamily1:column1', 'value3'
    
    # 默认返回最新的一条数据
    get 'tbl_test','rowKey1','columnFamily1:column1'
    
    # 返回3个
    get 'tbl_test','rowKey1',{COLUMN=>'columnFamily1:column1', VERSIONS=>3}
    # 返回2个
    get 'tbl_test','rowKey1',{COLUMN=>'columnFamily1:column1', VERSIONS=>2}
    

    在这里插入图片描述

    10.5 STARTROW

    ROWKEY起始行。会先根据这个key定位到region,再向后扫描

    # 语法
    scan '表名', { STARTROW => '行键名'}
    
    # 示例
    scan 'tbl_user', { STARTROW => 'vbirdbest'}
    

    在这里插入图片描述

    10.6 STOPROW :截止到STOPROW行,STOPROW行之前的数据,不包括STOPROW这行数据
    # 语法
    scan '表名', { STOPROW => '行键名'}
    
    # 示例
    scan 'tbl_user', { STOPROW => 'vbirdbest'}
    

    在这里插入图片描述

    10.7 LIMIT 返回的行数
    # 语法
    scan '表名', { LIMIT => 行数}
    
    # 示例
    scan 'tbl_user', { LIMIT => 2 }
    

    在这里插入图片描述

    11. FILTER条件过滤器

    过滤器之间可以使用AND、OR连接多个过滤器。

    ValueFilter 值过滤器
    # 语法:binary 等于某个值
    scan '表名', FILTER=>"ValueFilter(=,'binary:列值')"
    # 语法 substring:包含某个值
    scan '表名', FILTER=>"ValueFilter(=,'substring:列值')"
    
    # 示例
    scan 'tbl_user', FILTER=>"ValueFilter(=, 'binary:26')"
    scan 'tbl_user', FILTER=>"ValueFilter(=, 'substring:6')"
    

    在这里插入图片描述

    ColumnPrefixFilter 列名前缀过滤器
    # 语法 substring:包含某个值
    scan '表名', FILTER=>"ColumnPrefixFilter('列名前缀')"
    
    # 示例
    scan 'tbl_user', FILTER=>"ColumnPrefixFilter('birth')"
    # 通过括号、AND和OR的条件组合多个过滤器
    scan 'tbl_user', FILTER=>"ColumnPrefixFilter('birth') AND ValueFilter(=,'substring:26')"
    

    在这里插入图片描述

    rowKey字典排序

    Table中的所有行都是按照row key的字典排序的
    在这里插入图片描述

    三:HBase 常见错误

    hbase shell在使用的时候经常会报错,这里列举了几个错误:

    1. HBase创建不存在的表报已经存在错误 ERROR: Table already exists: !

    解决办法:

    # 1. 进入zookeeper client模式
    cd /usr/local/Cellar/hbase/1.2.9/bin
    hbase zkcli
    
    # 2. 在zk client模式下输入ls /hbase/table命令看到zombie table
    ls /hbase/table
    
    # 3. 删除表,TABLE_NAME为要删除的表名
    rmr /hbase/table/TABLE_NAME
    
    # 4. 重启hbase
    ./stop-hbase.sh
    ./start-hbase.sh
    
    2. ERROR: org.apache.hadoop.hbase.ipc.ServerNotRunningYetException: Server is not running yet
    # 使用jps查看是否有datanode服务
    jps
    
    删除hadoop 的临时目录
    /usr/local/Cellar/hadoop/3.1.1/libexec/tmp
    
    3. ERROR: Can’t get master address from ZooKeeper; znode data == null
    # 重启hbase
    ./stop-hbase.sh
    
    ./start-hbase.sh
    

    4. ERROR: org.apache.hadoop.hbase.PleaseHoldException: Master is initializing

    这个错误出现的原因很多,这里说一下我的错误原因是hbase-site.xml中的有个属性名配置错误, 网上有的是hbase.rootdir, name配置成这个有的时候会报错有的时候不会报错,报错的时候格式化一下hadoop然后再重新启动,这种方式有的时候能解决问题,有的时候解决不了。这里我将hbase.rootdir改为hbase.root.dir 就不报错了,不知道是不是版本不同属性名配置不同,我的hadoop版本为3.1.1,hbase版本为1.2.9

    <!-- 正确的配置的属性名应为hbase.root.dir而不是hbase.rootdir -->
    <property>
      <name>hbase.root.dir</name>
      <value>hdfs://localhost:8020/hbase</value>
    </property>
    

    相关文档

    HBase操作(Shell与Java API)https://blog.csdn.net/u013980127/article/details/52443155

    展开全文
  • Linux命令大全----常用文件操作命令

    万次阅读 多人点赞 2015-10-19 08:43:25
    本文主要讲了Linux命令大全----常用文件操作命令,并附有实例

              林炳文Evankaka原创作品。转载请注明出处http://blog.csdn.net/evankaka

            摘要:本文主要讲了Linux命令大全----常用文件操作命令,并附有实例

    ls

    这个命令是经常用到的,用来显示当前目录下有哪些文件 ,ls最常用的参数有三个: -a -l -F。
    ls -a
    说明:Linux上的文件以“.”开头的文件被系统视为隐藏文件,仅用ls命令是看不到他们的,而用ls -a除了显示 一般文件名外,连隐藏文件也会显示出来。

    ls -l(这个参数是字母L的小写,不是数字1)
    说明:这个命令可以使用长格式显示文件内容,如果需要察看更详细的文件资料,就要用到ls -l这个指令。

     第一个栏位,表示文件的属性。Linux的文件基本上分为三个属性:可读(r),可写(w),可执行(x)。但是这里有十个格子可以添(具体程序实现时,实际上是十个bit位)。第一个小格是特殊表示格,表示目录或连结文件等等,d表示目录,例如drwx------;l表示连结文件,如lrwxrwxrwx;如果是以一横“-”表示,则表示这是文件。其余剩下的格子就以每3格为一个单位。因为Linux是多用户多任务系统,所以一个文件可能同时被许多人使用,所以我们一定要设好每个文件的权限,其文件的权限位置排列顺序是(以-rwxr-xr-x为例):
      rwx(Owner)r-x(Group)r-x(Other)
      这个例子表示的权限是:使用者自己可读,可写,可执行;同一组的用户可读,不可写,可执行;其它用户可读,不可写,可执行。另外,有一些程序属性的执行部分不是X,而是S,这表示执行这个程序的使用者,临时可以有和拥有者一样权力的身份来执行该程序。一般出现在系统管理之类的指令或程序,让使用者执行时,拥有root身份。
      第二个栏位,表示文件个数。如果是文件的话,那这个数目自然是1了,如果是目录的话,那它的数目就是该目录中的文件个数了。
      第三个栏位,表示该文件或目录的拥有者。若使用者目前处于自己的Home,那这一栏大概都是它的账号名称。
      第四个栏位,表示所属的组(group)。每一个使用者都可以拥有一个以上的组,不过大部分的使用者应该都只属于一个组,只有当系统管理员希望给予某使用者特殊权限时,才可能会给他另一个组。
      第五栏位,表示文件大小。文件大小用byte来表示,而空目录一般都是1024byte,你当然可以用其它参数使文件显示的单位不同,如使用ls –k就是用kb来显示一个文件的大小单位,不过一般我们还是以byte为主。
      第六个栏位,表示创建日期。以“月,日,时间”的格式表示,如Aug 15 5:46表示8月15日早上5:46分。
      第七个栏位,表示文件名。我们可以用ls –a显示隐藏的文件名。

    ls –F(注意,是大写的F)
    说明:使用这个参数表示在文件的后面多添加表示文件类型的符号,例如*表示可执行,/表示目录,@表示连结文件,这都是因为使用了-F这个参数。但是现在基本上所有的Linux发行版本的ls都已经内建了-F参数,也就是说,不用输入这个参数,我们也能看到各种分辨符号。

    当然,以上命令还可以一起用,如下

    cd
     Linux cd 命令可以说是Linux中最基本的命令语句,其他的命令语句要进行操作,都是建立在使用 cd 命令上的。切换当前目录至dirName
    cd /  

    说明:进入系统根目录,上面命令执行完后拿ls命令看一下,当前目录已经到系统根目录了 


    cd .. 或者 cd .. // 

    说明:进入系统根目录可以使用“ cd .. ”一直退,就可以到达根目录 


    cd ../.. //
    说明:使用cd 命令实现进入当前目录的父目录的父目录。 


    mkdir、rmdir
      mkdir命令用来建立新的目录,rmdir用来删除已建立的目录

    mkdir创建目录,如果目录存在会报错

    rmdir删除目录


    注意,如果linlin内容非空


    rmdir 命令只能删除空的文件夹,如果文件夹非空,将不能删除,它也没有-f选项,所以你的命令都是错的。
    要删除非空的文件夹,可以使用rm命令,加rf两个选项,如:


    cp

        cp命令用来将一个或多个源文件或者目录复制到指定的目的文件或目录。它可以将单个源文件复制成一个指定文件名的具体的文件或一个已经存在的目录下。cp命令还支持同时复制多个文件,当一次复制多个文件时,目标文件参数必须是一个已经存在的目录,否则将出现错误。

    -a:此参数的效果和同时指定"-dpR"参数相同;
     -d:当复制符号连接时,把目标文件或目录也建立为符号连接,并指向与源文件或目录连接的原始文件或目录;
    -f:强行复制文件或目录,不论目标文件或目录是否已存在;
     -i:覆盖既有文件之前先询问用户;
     -l:对源文件建立硬连接,而非复制文件;
     -p:保留源文件或目录的属性; 
    -R/r:递归处理,将指定目录下的所有文件与子目录一并处理;
     -s:对源文件建立符号连接,而非复制文件;
     -u:使用这项参数后只会在源文件的更改时间较目标文件更新时或是名称相互对应的目标文件并不存在时,才复制文件;
     -S:在备份文件时,用指定的后缀“SUFFIX”代替文件的默认后缀;
     -b:覆盖已存在的文件目标前将目标文件备份; -v:详细显示命令执行的操作

    具体用法是:cp –r 源文件(source)  目的文件(target)。 参数r是指连同源文件中的子目录一同拷贝。

    如下,将/home/linlin1下的linlin.c复制到/home/linlin2下


    如下,将/home/linlin1下的linlin.c复制到/home/linlin2下并改名为hello.c


    我们在Linux下使用cp命令复制文件时候,有时候会需要覆盖一些同名文件,覆盖文件的时候都会有提示:需要不停的按Y来确定执行覆盖。文件数量不多还好,但是要是几百个估计按Y都要吐血了,于是折腾来半天总结了一个方法:

    cp aaa/* /bbb 复制目录aaa下所有到/bbb目录下,这时如果/bbb目录下有和aaa同名的文件,需要按Y来确认并且会略过aaa目录下的子目录。
    cp -r aaa/* /bbb 这次依然需要按Y来确认操作,但是没有忽略子目录。
    cp -r -a aaa/* /bbb 依然需要按Y来确认操作,并且把aaa目录以及子目录和文件属性也传递到了/bbb。 
    cp -r -a aaa/* /bbb 成功,没有提示按Y、传递了目录属性、没有略过目录。

    把一个文件夹下的内容全部复制到另一个文件夹下



    rm
      这个命令是用来删除文件的,和dos下面的rm(删除一个空目录)是有区别的,大家千万要注意。rm命令常用的参数有三个: -i,-r,-f。
      

        -f, --force    忽略不存在的文件,从不给出提示。
        -i, --interactive 进行交互式删除
        -r, -R, --recursive   指示rm将参数中列出的全部目录和子目录均递归地删除。
        -v, --verbose    详细显示进行的步骤
          	--help     显示此帮助信息并退出
          	--version  输出版本信息并退出
      rm –r 目录名:这个操作可以连同这个目录下面的子目录都删除,功能上和rmdir相似。
      rm –f 文件名(目录名):这个操作可以进行强制删除。

    一般将r和f组合-rf一起使用

    如下,交互删除


    全部强制删除



    mv
      这个命令的功能是移动目录或文件,引申的功能是给目录或文件重命名。当使用该命令来移动目录时,他会连同该目录下面的子目录也一同移走。

    -b :若需覆盖文件,则覆盖前先行备份。 
    -f :force 强制的意思,如果目标文件已经存在,不会询问而直接覆盖;
    -i :若目标文件 (destination) 已经存在时,就会询问是否覆盖!
    -u :若目标文件已经存在,且 source 比较新,才会更新(update)
    -t  : --target-directory=DIRECTORY move all SOURCE arguments into DIRECTORY,即指定mv的目标目录,该选项适用于移动多个源文件到一个目录的情况,此时目标目录在前,源文件在后。
    文件改名

    mv 原文件(目录)名 新的文件(目录)名。 


    文件 移动



    du,df
      du命令可以显示目前的目录所占的磁盘空间,df命令可以显示目前磁盘剩余的磁盘空间。如果du命令不加任何参数,那么返回的是整个磁盘的使用情况,如果后面加了目录的话,就是这个目录在磁盘上的使用情况

    查看当前目录以及子目录的大小:


    查看整个磁盘大小


    cat

         cat主要有三大功能:
    1.一次显示整个文件。$ cat filename
    2.从键盘创建一个文件。$ cat > filename
    只能创建新文件,不能编辑已有文件.
    3.将几个文件合并为一个文件: $cat file1 file2 > file
    参数:

    -n 或 --number 由 1 开始对所有输出的行数编号
    -b 或 --number-nonblank 和 -n 相似,只不过对于空白行不编号
    -s 或 --squeeze-blank 当遇到有连续两行以上的空白行,就代换为一行的空白行
    -v 或 --show-nonprinting

    它的用法如下:

      cat text 显示text这个文件;

      cat file1 file2 依顺序显示file1,file2的内容;

      cat file1 file2>file3 把file1,file2的内容结合起来,再“重定向(>)”到file3文件中。
      “〉”是一个非常有趣的符号,是往右重定向的意思,就是把左边的结果当成是输入,然后输入到file3这个文件中。这里要注意一点是file3是在重定向以前还未存在的文件,如果file3是已经存在的文件,那么它本身的内容被覆盖,而变成file1+file2的内容。如果〉左边没有文件的名称,而右边有文件名,例如:

    把 text.c和 text1.c的档案内容加上行号(空白行不加)之后将内容附加到 text2.c 里。

      另外,如果你使用如下的指令:
      cat file1>>file2:这将变成将file1的文件内容“附加”到file2的文件后面,而file2的内容依然存在,这种重定向符〉〉比〉常用,可以多多利用。 


    more,less
      这是两个显示一般文本文件的指令。如果一个文本文件太长了超过一个屏幕的画面,用cat来看实在是不理想,就可以试试more和less两个指令。More指令可以使超过一页的文件临时停留在屏幕,等你按任何的一个键以后,才继续显示。而less除了有more的功能以外,还可以用方向键往上或往下的滚动文件,所以你随意浏览,阅读文章时,less是个非常好的选择。 

    more:选项 文件名

    +n 从笫n行开始显示
    -n 定义屏幕大小为n行
    +/pattern 在每个档案显示前搜寻该字串(pattern),然后从该字串前两行之后开始显示
    -c 从顶部清屏,然后显示
    -d 提示“Press space to continue,’q’ to quit(按空格键继续,按q键退出)”,禁用响铃功能
    -l 忽略Ctrl+l(换页)字符
    -p 通过清除窗口而不是滚屏来对文件进行换页,与-c选项相似
    -s 把连续的多个空行显示为一行
    -u 把文件内容中的下画线去掉

    在每个档案显示前搜寻该字串lin,然后从该字串前两行之后开始显示 


    less

    less 工具也是对文件或其它输出进行分页显示的工具,应该说是linux正统查看文件内容的工具,功能极其强大。less 的用法比起 more 更加的有弹性。在 more 的时候,我们并没有办法向前面翻, 只能往后面看,但若使用了 less 时,就可以使用 [pageup] [pagedown] 等按键的功能来往前往后翻看文件,更容易用来查看一个文件的内容!除此之外,在 less 里头可以拥有更多的搜索功能,不止可以向下搜,也可以向上搜。

    less 选项 文件名

    选项

    -b <缓冲区大小> 设置缓冲区的大小
    -e  当文件显示结束后,自动离开
    -f  强迫打开特殊文件,例如外围设备代号、目录和二进制文件
    -g  只标志最后搜索的关键词
    -i  忽略搜索时的大小写
    -m  显示类似more命令的百分比
    -N  显示每行的行号
    -o <文件名> 将less 输出的内容在指定文件中保存起来
    -Q  不使用警告音
    -s  显示连续空行为一行
    -S  行过长时间将超出部分舍弃
    -x <数字> 将“tab”键显示为规定的数字空格
    /字符串:向下搜索“字符串”的功能
    ?字符串:向上搜索“字符串”的功能
    n:重复前一个搜索(与 / 或 ? 有关)
    N:反向重复前一个搜索(与 / 或 ? 有关)
    b  向后翻一页
    d  向后翻半页
    h  显示帮助界面
    Q  退出less 命令
    u  向前滚动半页
    y  向前滚动一行
    空格键 滚动一行
    回车键 滚动一页
    [pagedown]: 向下翻动一页
    [pageup]:   向上翻动一页

    退出按Q

    向下搜索含lin的字符串


    在Linux系统中有三种命令可以用来查阅全部的文件,分别是cat、more和less命令。它们查阅文件的使用方法也比较简单都是 命令 文件名 ,但是三者又有着区别。
    1.cat命令可以一次显示整个文件,如果文件比较大,使用不是很方便;
    2.more命令可以让屏幕在显示满一屏幕时暂停,此时可按空格健继续显示下一个画面,或按Q键停止显示。
    3.less命令也可以分页显示文件,和more命令的区别就在于它支持上下键卷动屏幕,当结束浏览时,只要在less命令的提示符“: ”下按Q键即可。
    另外,多数情况下more和less命令会配合管道符来分页输出需要在屏幕上显示的内容。

    tail

        也是用于用于查看文件内容 

    tail语法格式:
    tail [ -f ] [ -c Number | -n Number | -m Number | -b Number | -k Number ] [ File ]
    或者
    tail [ -r ] [ -n Number ] [ File ]
    使用说明:
    tail 命令从指定点开始将 File 参数指定的文件写到标准输出。如果没有指定文件,则会使用标准输入。 Number 变量指定将多少单元写入标准输出。 Number 变量的值可以是正的或负的整数。如果值的前面有 +(加号),从文件开头指定的单元数开始将文件写到标准输出。如果值的前面有 -(减号),则从文件末尾指定的单元数开始将文件写到标准输出。如果值前面没有 +(加号)或 -(减号),那么从文件末尾指定的单元号开始读取文件。
    主要参数:
    -b Number 从 Number 变量表示的 512 字节块位置开始读取指定文件。
    -c Number 从 Number 变量表示的字节位置开始读取指定文件。
    -f 如果输入文件是常规文件或如果 File 参数指定 FIFO(先进先出),那么 tail 命令不会在复制了输入文件的最后的指定单元后终止,而是继续从输入文件读取和复制额外的单元(当这些单元可用时)。如果没有指定 File 参数,并且标准输入是管道,则会忽略 -f 标志。tail -f 命令可用于监视另一个进程正在写入的文件的增长。
    -k Number 从 Number 变量表示的1KB 块位置开始读取指定文件。
    -m Number 从 Number 变量表示的多字节字符位置开始读取指定文件。使用该标志提供在单字节和双字节字符代码集环境中的一致结果。
    -n Number 从首行或末行位置来读取指定文件,位置由 Number 变量的符号(+ 或 - 或无)表示,并通过行号 Number 进行位移。
    -r 从文件末尾以逆序方式显示输出。-r 标志的缺省值是以逆序方式显示整个文件。

    如果文件大于 20,480 字节,那么-r标志只显示最后的 20,480 字节。 -r 标志只有 与 -n 标志一起时才有效。否则,就会将其忽略。

    tail -f 命令可用于监视另一个进程正在写入的文件的增长。 特别是在看日志时非常有用,你实时更新了日志,它就实时显示出来



    pwd
      pwd [--help][--version]
      说明:执行pwd指令可立刻得知您目前所在的工作目录的绝对路径名称。 

    clear
      这个命令是用来清除屏幕的,它不需要任何参数

    grep
      用于查找文件中符合字符串的哪行。
      参数说明:

        -a :将 binary 文件以 text 文件的方式搜寻数据
      -c :计算找到 '搜寻字符串' 的次数
      -i :忽略大小写的不同,所以大小写视为相同
      -n :顺便输出行号
      -v :反向选择,亦即显示出没有 '搜寻字符串' 内容的那一行! 
    如。显示包含st的行,及其行号

    将没有出现st的给显示出来


    根据文件内容递归查找目录

    # grep ‘energywise’ *           #在当前目录搜索带'energywise'行的文件
    # grep -r ‘energywise’ *        #在当前目录及其子目录下搜索'energywise'行的文件
    # grep -l -r ‘energywise’ *     #在当前目录及其子目录下搜索'energywise'行的文件,但是不显示匹配的行,只显示匹配的文件

    如下


    grep功能是很强大的,这里只简单说明了一下,有兴趣的同学自己下来研究下吧!

    find

      $ find  -name "*.txt" -print 用于查找所有的‘ *.txt’文件在当前目录及子目录中
      $ find  -name "[A-Z]*" -print 用于当前目录及子目录中查找文件名以一个大写字母开头的文件
      $ find /etc -name "host*" -print 在/etc目录中查找文件名以host开头的文件
      $find  -name "[a-z][a-z][0--9][0--9].txt" -print 在当前目录查找文件名以两个小写字母开头,跟着是两个数字,最后是.txt的文件
      如,当前目录中查找以.c结尾的文件


    1.在某目录下查找名为“elm.cc”的文件
    find /home/lijiajia/ -name elm.cc
     
    2.查找文件名中包含某字符(如"elm")的文件
    find /home/lijiajia/ -name '*elm*'
    find /home/lijiajia/ -name 'elm*'
    find /home/lijiajia/ -name '*elm'
     
    3.根据文件的特征进行查询
    find /home/lijiajia/ -amin -10        #查找在系统中最后10分钟访问的文件
    find /home/lijiajia/ -atime -2        #查找在系统中最后48小时访问的文件
    find /home/lijiajia/ -empty           #查找在系统中为空的文件或者文件夹
    find /home/lijiajia/ -group cat       # 查找在系统中属于groupcat 的文件(试了,命令不对。)
    find /home/lijiajia/ -mmin -5         # 查找在系统中最后5 分钟里修改过的文件
    find /home/lijiajia/ -mtime -1        #查找在系统中最后24 小时里修改过的文件
    find /home/lijiajia/ -nouser          #查找在系统中属于作废用户的文件(不明白是什么意思)
    find /home/lijiajia/ -amin 10         #查找在系统中最后10分钟访问的文件
    find /home/ftp/pub -user lijiajia     #查找在系统中属于lijiajia这个用户的文件
    (PS:以上都是在 /home/lijiajia/文件夹下进行的操作)
     
    4.使用混合查找方式查找文件
    find /tmp -size +10000000c -and -mtime +2      #查找/tmp目录中大于10000000字节并且在48小时内修改的某个文件
    find /tmp -user tom -or -user george           #查找/tmp目录中属于tom或者george这两个用户的文件
    find /tmp ! -usr fred                          #查找/tmp目录中不属于fred的文件
     
    5.查找并显示文件
    find /home/lijiajia/ -name 'elm.cc' -ls        #在目录下查找名为“elm.cc”的文件,并显示这些文件的信息



    展开全文
  • 【LaTeX入门】05 换行 换 换页 首行缩进等命令
  • linux中systemctl详细理解及常用命令

    万次阅读 多人点赞 2019-06-28 16:16:52
    一、systemctl理解 Linux 服务管理两种方式service和systemctl systemd是Linux系统最新的初始化...systemd对应的进程管理命令是systemctl 1. systemctl命令兼容了service 即systemctl也会去/etc/init.d目录下...
  • 简介 Tcl 表示工具命令语言(Tool Command Language),它是一种流行的脚本编制语言,最初由加州大学伯克利分校的 John Ousterhout 教授开发。John Ousterhout 打算将 Tcl 作为一种将其它程序组件粘合在一起的语言,...
  • 文章目录linux 系统命令总结大全关于作者**作者介绍**0.IP 地址相关命令0.1 ifconfig 命令 ---显示网络设备信息02.ip 命令 ---显示与操作路由03.dhclient 命令 --- 动态获取或释放IP地址04.nmtui ---界面修改网卡...
  • ADB常用命令及其用法大全

    万次阅读 多人点赞 2019-02-23 22:03:15
    本文主要记述ADB的常用命令,关于ADB用法大全,可参考文末链接 ADB简介: ADB,即 Android Debug Bridge,它是 Android 开发/测试人员不可替代的强大工具,也是 Android 设备玩家的好玩具。安卓调试桥 (Android ...
  • gdb基础命令和常用操作补充

    千次阅读 2015-01-23 11:42:51
    GDB是Unix下的一个程序调试工具,类似于windows下面的VC调试器,区别在于GDB采用全命令行控制。 使用GDB需要在编译时使用-g选项,gcc支持-g –O选项同时使用,但如果还在调试阶段,尽量不要-O2,也不要删除(strip)...
  • Linux系统常用的基本命令

    万次阅读 多人点赞 2018-08-15 15:11:08
    下面开始介绍。 一、查看哪个用户登录的系统 1、users命令 2、whoami命令或者who am i命令 二、查看哪些用户在系统上工作 1、who命令 2、w命令 三、查看登录Linux系统所使用的终端 1、tty命令 四...
  • VIM折叠代码命令

    万次阅读 2012-07-13 12:01:51
    在VIM下,折叠文本一般情况下我是使用...发现可以使用命令模式:开始行号,结束行号folder命令就可以折叠了, 同样多行缩进可以使用:110,120>来将110行到120行缩进 复制:110,120 yank 复制到默认寄存器 或者:110,120 y
  • 预处理命令

    千次阅读 多人点赞 2019-07-27 22:40:10
    一、预处理命令 二、#include 1.尖括号/引号引入标准头文件区别 2.#include 用法举例 三、C语言宏定义----#define 四、带参数的宏定义 对带参宏定义的说明 五、C语言带参宏定义和函数的区别 六、C语言宏...
  • Linux系统常用基本命令总结

    万次阅读 多人点赞 2018-11-13 22:42:20
    Linux基本命令 Linux的简介 Linux的厂商 Linux的目录结构 基于虚拟机的环境搭建 常用命令与示例 一、文件基本操作命令 1. ls命令 2. pwd命令 3. mkdir命令 4. cd命令 5. touch命令 6. cp命令 7. mv命令...
  • ps 命令详解

    万次阅读 多人点赞 2016-12-03 16:42:03
    From:... 进程和作业管理命令:http://man.linuxde.net/sub/进程和作业管理 Linux 关于 进程/线程 的命令 kill 和 pgrep 和 pidof 和 awk 和 pkill 和 killall:https://blog.csdn.net/freeki...
  • LaTeX 各种命令,符号

    万次阅读 多人点赞 2016-06-12 15:27:42
    函数、符号及特殊字符 声调 语法 效果 语法 效果 语法 效果 \bar{x} latex数学符号表(2)" style="border:none; max-width:100%"> \acute{\eta} latex数学符号表(2)" style="border:none;...lat
  • 使用#define指令进行宏定义 宏定义的功能是用一个标识符来表示字符串,标识符称为宏名。在预编译处理时,对程序中出现的宏名,在程序中出现的宏名,都用宏定义中出现的字符串去代替。  #define 指令的形式是: #...
  • Dos命令大全完整版

    万次阅读 多人点赞 2018-07-18 10:14:03
    DOS(磁盘操作系统)命令,是DOS操作系统的命令,是一种面向磁盘的操作命令,主要包括目录操作类命令、磁盘操作类命令、文件操作类命令和其它命令。 使用技巧 DOS命令不区分大小写,比如C盘的Program Files,在dos...
  • top命令是Linux下常用的性能分析工具,能够实时显示系统中各个进程的资源占用状况,类似于Windows的任务管理器。 可以直接使用top命令后,查看%MEM的内容。可以选择按进程查看或者按用户查看,如想查看oracle用户的...
  • 定义有无参数宏定义和带参数宏定义两种。  无参数的宏定义的一般形式为  # define 标识符 字符序列 其中# define之后的标识符称为宏定义名(简称宏名),要求宏名与字符序列之间用空格符分隔。这种宏定义要求...
  • ping命令详解

    万次阅读 多人点赞 2018-11-02 22:53:38
    Linux系统的ping命令是常用的网络命令,它通常用来测试与目标主机的连通性,我们经常会说“ping一下某机器,看是不是开着”、不能打开网页时会说“你先ping网关地址192.168.1.1试试”。它通过发送ICMP ECHO_REQUEST...
  • C++中的宏定义

    千次阅读 2016-07-06 11:08:07
    其中的“#”表示这是一条预处理命令。凡是以“#”开头的均为预处理命令。“define”为宏定义命令。“标识符”为所定义的宏名。“字符串”可以是常数、表达式、格式串等。 在前面介绍过的符号常量的定义就是一种无参
  • 换行命令 \\:换行。 \\[offset]:换行,并且与下一行的行间距为原来行间距+offset。 \newline:与\\相同。 \linebreak:强制换行,与\newline的区别为\linebreak的当前行分散对齐。 分段命令 \...
  • C语言宏定义和宏定义函数

    千次阅读 2016-03-13 19:55:59
     在软件开发过程中,经常有一些常用或者通用的功能或者代码,这些功能既可以写成函数,也可以封装成为宏定义。那么究竟是用函数好,还是宏定义好?这就要求我们对二者进行合理的取舍。  我们来看一个例子,比较...
  • echo 命令总结

    千次阅读 多人点赞 2020-03-19 17:03:35
    echo命令的功能是在显示器上显示一文字,一般起到一个提示的作用。此外,也可以直接在文件中写入要写的内容。也可以用于脚本编程时显示某一个变量的值,或者直接输出指定的字符串。 echo命令的语法是: echo [选项...
  • React 语法之let和const命令

    万次阅读 2016-08-30 09:18:17
    let命令基本用法ES6新增了let命令,用来声明变量。它的用法类似于var,但是所声明的变量,只在let命令所在的代码块内有效。{ let a = 10; var b = 1; } a // ReferenceError: a is not defined. b // 1 上面代码...
  • DOS常用命令(从入门到精通)

    万次阅读 多人点赞 2018-08-26 11:27:24
    DOS命令学习 一、DOS使用常识 DOS(Disk Operating System)是一个使用得十分广泛的磁盘操作系统。 常见的DOS有两种:IBM公司的PC-DOS和微软公司的MS-DOS,它们的功能、命令用途格式都相同,我们常用的是MS-DOS。...
  • ftp登陆命令

    千次阅读 2018-10-16 22:19:26
    一、shelll示例: cd /PATH_YOU_WANT_TO_UPLOAD(DOWNLOAD)ftp -niv &amp;lt;&amp;lt;- EOFopen IP_ADDRESSuser USERNAME ...下面详细讲解以下这代码: &amp;nbsp;&amp;nbsp;&amp;nb...
  • DOS批处理命令 For循环命令详解!

    万次阅读 2013-01-17 17:16:28
    for命令是一种对一系列对象依次循环执行同一个或多个命令的在命令行或批处理中运行的命令,结合一些Windows管理中的程序后,其处理功能强大、应用灵活方便程度令人刮目相看。但是,其帮助信息也因此复杂往往令初学者...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 207,743
精华内容 83,097
关键字:

下面表示段定义结束的命令是