这次讲的是关于bash命令行中的外部命令grep的一些事情。历史1grep是一个命令行工具,最初用于Unix操作系统。给定文件列表或标准输入,grep搜索与一个或多个正则表达式匹配的文本,并仅输出匹配(或不匹配)的行或文本。grep是最初由KenThompson编写的应用程序。grep原本是ed下的一个应用,名字来源于g/re/p(globallysearcharegularexpressionandprint,globalsearchandprintwithregularexpression)。在ed下,输入命令g/re/p后,所有符合定义样式的字符串都会以行为单位打印出来。1973年,第四版Unix,grep首次出现在手册页中。以上主要来自wiki。函数grep使用正则表达式搜索文本并打印匹配的行。作为输入文本,它可以来自标准输入或来自(任意多个,通配符表示)文件。新版grep还支持遍历当前目录下子文件夹的所有文件,进行正则表达式匹配和查找。grep的典型选项包括:模式选择和解释:-E使用模板样式作为扩展的普通表达式,这意味着使用可以使用扩展的正则表达式。(扩展正则表达式)-F将模板样式视为固定字符串列表。(换行符分隔的字符串)-G使用模板样式作为基本正则表达式。(基本正则表达式)-P使用模板样式作为Perl表示法。(Perl正则表达式)-e指定一个字符串作为用于查找文件内容的模板模式。-f<模板文件>指定一个模板文件,其内容有一个或多个模板样式,让grep找到满足模板条件的文件内容,格式为每一列的模板样式。-i忽略字符大小写的差异。-w只显示匹配整个单词的列。-x只显示匹配所有列的列。杂项:-v反转查找。-s不显示错误信息。输出控制:-b显示输出行距文件开头的字节偏移量。-c计算与模板样式匹配的列数。-h在显示符合模板样式的列之前,不指明该列所属的文件名。-H在显示符合模板样式的列之前标记列的文件名。-l列出其内容与指定模板模式匹配的文件的名称。-L列出内容不符合指定模板模式的文件名。-n表示显示匹配模板样式的列之前的列号。-o只输出文件的匹配部分。-q不显示任何信息。-R/-r该参数的作用与指定“-drecurse”参数相同。内容控制:-B<显示列数>除了显示符合模板样式的行,还显示该行之前的内容。-A<显示的列数>除了显示符合模板样式的行,还显示该行之后的内容。-C<显示列数>或-<显示列数>除了显示符合模板样式的列外,还显示该列前后的内容。详细选项请参考grep--help的输出。用法:grep[OPTION]...PATTERN[FILE]...在每个FILE中搜索PATTERN。例如:grep-i'helloworld'menu.hmain.c如需完整的参考手册,请使用命令行mangrep和infogrep进行搜索。基本用法2在文件中搜索一个单词,命令将返回包含“match_pattern”的文本行:grepmatch_patternfile_namegrep'match_pattern'file_namegrep"match_pattern"file_name上面三个命令等同于grep。不同的是,单引号可以防止match_pattern中出现空格,禁止嵌套的bash计算(比如$var变量嵌入),而双引号支持bash变量扩展和bash命令嵌套,同时具有单引号的效果计算,bash算术表达式求值和扩张等等。在多个文件中查找:grep"match_pattern"file_1file_2file_3...输出除-v选项以外的所有行:grep-v"match_pattern"file_name又如ps-auxef|grepjava|grep-vgrepheregrep-vgrep的意思从以前的结果中排除带有grep文本的实例(所有java运行实例)。其实这是为了排除grepjava命令的实例,这样我们得到的是纯java运行的实例。标记匹配颜色--color=auto选项:grep"match_pattern"file_name--color=auto使用正则表达式-E选项:grep-E"[1-9]+"#oregrep"[1-9]+"egrep表示使用扩展正则表达式语法。只输出文件的匹配部分-o选项:echothisisatestline。|grep-o-E"[a-z]+\."line.echo这是一条测试线。|egrep-o"[a-z]+\."行。统计文件或文本中包含匹配字符串的行数-c选项:grep-c"text"file_name输出包含匹配字符串的行数-n选项:grep"text"-nfile_name或catfile_name|grep"text"-n#Multiplefilesgrep"text"-nfile_1file_2打印样式匹配的字符或字节偏移量:echogunisnotunix|grep-b-o"not"7:not#一行中字符串的字符值是从该行的第一个字符开始计算的,起始值为0。选项-b-o一般总是一起使用。搜索多个文件,查找匹配文本在哪些文件中:grep-l"text"file1file2file3...匹配模式忽略字符大小写:echo"helloworld"|grep-i"HELLO"hellooption-e指定多种匹配样式:echothisisatextline|grep-e"is"-e"line"-oisline#也可以使用-f选项匹配多个样式,在样式文件字符中逐行写出匹配的样式。catpatfileaaabbbechoaaabbbcccdddeee|grep-fpatfile-ogreprecursivesearchforfiles递归搜索多级目录中的文本:grep"text"。-r-n#。指示当前目录。在grep搜索结果中包含或排除指定文件:#只在目录grep"main()"中的所有.php和.html文件中递归搜索字符"main()"。-r--include*.{php,html}#排除搜索结果中的所有README文件grep"main()".-r--exclude"README"#在搜索结果中排除filelist文件列表中的文件grep"main()".-r--exclude-fromfilelistgrepandxargswith0-valuebytesuffix:#Testfile:echo"aaa">file1echo"bbb">file2echo"aaa">file3grep"aaa"文件*-lZ|xargs-0rm#执行完后会执行删除file1和file3,grep输出使用-Z选项指定一个零值字节作为终结符文件名(\0),xargs-0读取输入并用a分隔文件名零值字节终止符,然后删除匹配的文件,-Z通常与-l结合使用。grepsilentoutput:grep-q"test"filename#不会输出任何信息,命令运行成功则返回0,失败则返回非零值。通常用于条件测试。打印匹配文本前后的行:#显示匹配某个结果后的3行,使用-A选项:seq10|grep"5"-A35678#显示匹配某个结果前的3行,使用-B选项:seq10|grep"5"-B32345#显示匹配某个结果的前三行和后三行,使用-C选项:seq10|grep"5"-C32345678#如果有多个匹配结果,每个匹配结果之间用"--"作为分隔符:echo-e"a\nb\nc\na\nb\nc"|grepa-A1ab--abgrep-P表示启用perl语法规则。此时您可以使用Perl正则语法编写规则。Perl正则表达式语法,也称为PCRE表达式,可以参考Wiki中完整的PCRE表达式集。常见的成语是递归地在文件夹中查找文本字符串。我不知道哪些文件包含幻想文字描述。你可以这样找到它:grep-PHni'fantasy'*-r该命令将列出当前文件夹中的所有内容。幻想文件,列出它们的文件名和包含幻想文本及其行号的行。如果还需要查看匹配文本前后的上下文,可以使用:grep-PHni'fantasy'*-r-C3-P表示使用Perl正则表达式语法-H表示打印出文件名where找到匹配行-n表示打印显示匹配行的行号-i表示忽略大小写-C3表示列出前后三行。-B3表示前三行也被列出。-A3表示接下来的三行也被列出。当findipaddress使用-o参数时,grep往往是用来提取特定模式的文本内容,而不是输出整行匹配。例如:$ipaddr1:lo:mtu65536qdiscnoqueuestateUNKNOWNgroupdefaultqlen1000link/loopback00:00:00:00:00:00brd00:00:00:00:00:00inet127.0.0.1/8scopehostlovalid_lftforeverpreferred_lftforever2:ens3:mtu1500qdiscmqstateUPgroupdefaultqlen1000link/ether56:00:01:c6:ab:01brdff:ff:ff:ff:ff:ffinet217.179.87.159/23brd217.179.87.255范围全局动态ens3valid_lft63125secpreferred_lft63125sec3:ens7:mtu1500qdiscnoop状态DOWN组默认qlen1000/以太5a:00:01:c6:ab:01brdff:ff:ff:ff:ff:ff$ip地址|grep-Po'inet\d+\.\d+\.\d+\.\d+'|grep-v'inet127'|grep-Po'\d+.+'217.179.87.159这里,第一个表达式会把'inetxxxxxx'的两行提取出来,如:inet127.0.0.1inet217.179.87.159表达式中第一个127.0.0.1的行会被排除,并且在第三个表达式中去掉inet前缀,最终我们会得到我们想要的IP地址。可以使用类似的方法来提取IPv6地址。当然,在第三个表达式中提取'inet217.179.87.159'是一个累人的方法。其实这里我们会用awk截掉前半部分:awk'{print$2}'。这个短语把输入的文本按照空格分成n个小段,$2代表第二段,也就是我们要的IP地址。ports如果想找出当前主机中监听端口的服务,可以使用lsof命令的输出:$sudolsof-Pni|grepLISTENsshd858root3uIPv4195720t0TCP*:22(LISTEN)sshd858root4uIPv6195820t0TCP*:22(LISTEN)nginx6170root9uIPv4539518270t0TCP*:443(LISTEN)nginx6170root10uIPv4539518280t0TCP*:8060(LISTEN)nginx6170root139uIPv10590IPv4*:,我们可以写一个常用的命令函数ports,放到.bashrc文件中,这样我们就可以很方便的查看端口号。这个函数可以这样写:ports(){localx=$1if["$x"==""];然后sudolsof-Pni|grep-P'LISTEN|UDP'elsesudolsof-Pni|grep-P'LISTEN|UDP'|grep":$x"fi}然后我们可以这样使用它:portsports443ports22注意,你最好将你的Linux帐户调整为免密码sudo,否则你在使用ports获得sudo状态时可能需要输入你自己的密码。当然,如果你只想查看你启动的服务的端口号,可以去掉sudo命令。has-user,has-group如何检测linux账号是否存在?Linux中没有专门用于此检测的通用命令。如果用户存在,通常像useradd这样的命令会返回失败,但这不是检测它的正确方法。出于我们的目的,我们只能自己解释/etc/passwd文件。这个文件会列出系统中所有的账户,它的格式是这样的:root:x:0:0:root:/root:/bin/bashdaemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologinbin:x:2:2:bin:/bin:/usr/sbin/nologinsys:x:3:3:sys:/dev:/usr/sbin/nologinsync:x:4:65534:sync:/bin:/bin/sync...所以,判断一个用户是否存在,只需要判断第一个字段即可。显然,awk适用于此:$cat/etc/passwd|awk-F:'{print$1}'rootdaemonbinsyssync但是本文还是使用grep来解决问题:has-user(){localname=${1:-root}cat/etc/passwd|grep-q"^$name"}has-user'joe'&&echo'joeexists'||'joenotexists'类似的,我们也可以定义一个类似的函数has-group:has-group(){localname=${1:-root}cat/etc/group|grep-q"^$name"}has-groupstaff&&echo'staff组存在'||echo'staffgroupnotexists'more下面,我们给出一些实际例子:functionfind_ip(){ipaddr|grep-Poi"inet((192.168.\d+.\d+)|(172.\d+.\d+.\d+)|(10.\d+.\d+.\d+))"|grep-Poi"\d+.\d+.\d+.\d+";}functionfind_ip_uniq(){ipaddr|grep-Poi"inet((192.168.\d+.\d+)|(172.\d+.\d+.\d+)|(10.\d+.\d+.\d+))"|grep-Poi"\d+.\d+.\d+.\d+"|grep-v'\.255'|head-n1;}genpasswd(){strings/dev/urandom|grep-oP'[[:alnum:]]|[\#\%\@\&\^]'|head-n"${1:-16}"|tr-d'\n';echo;}结语grep和awk、sed是Linux的三大工具,很大程度上代表了Linux哲学的设计理念,即小、专、合。使用像grep这样的工具最大的技巧就是分解目标行为:获取源文本,过滤源文本,构造结果输出。本文只讲解基本用法,还需各位自行脑洞大开。参考https://zh.wikipedia.org/wiki...http://man.linuxde.net/grep>...