设为首页 加入收藏

TOP

别催了,别催了,这篇文章我一次性把Shell的内容说完(一)
2023-07-25 21:41:52 】 浏览:52
Tags:别催了 文章我 Shell 容说完

Shell 搜索与匹配

1、在文件中查找字符串

grep 命令可以搜索文件,查找指定的字符串。

$ grep myvar *.c

在这个例子中,我们搜索的文件全都位于当前目录下。因此,我们只使用了简单的 shell 模式 *.c 来匹配以 .c 结束的文件,并没有在文件名前再添加路径。

但并非所有待搜索的文件都老老实实地待在当前目录下。但因为shell 并不在意你输入多少路径名,所以我们也可以这么写:

$ grep myvar ../lib/*.c ../server/*.c ../cmd/*.c */*.c

如果待搜索的文件不止一个,grep 会在输出前加上文件名以及冒号,然后是该文件中包含 grep 搜索内容的文本。

grep 的第一个(非选项)参数可以是一个简单的字符串,也可以是更复杂的正则表达式(regexp)。正则表达式不同于 shell 的模式匹配,尽管两者有时看起来差不多。

常见错误

忘记指定 grep 的输入,例如 grep myvar。这种情况下,grep 会认为你要从 STDIN 提供输入,而你以为它会读取文件,于是 grep 就干等着,无所事事。

2、只显示包含搜索结果的文件名

你需要找出包含特定字符串的文件,但是不想看到其所在的文本行,只用输出文件名即可,经常在线上为了搜索配置文件。

用 grep 的 -l 选项仅显示文件名即可,如下:

$ grep -l myvar *.c
both.c
good.c
somio.c
$

如果在一个文件中找到了多次匹配,grep 仍然只输出该文件名一次。如果没有找到匹配,则什么都不输出。

由于这些文件包含了你要查找的字符串,如果想据此构建一个待处理

文件的列表,选项 -l 就能派上用场了。将 grep 命令放进 $(),然后就可以在命令行上使用这些文件名了,如下:

rm -i $(grep -l 'This file is obsolete' * ) 

删除包含字符串“This file is obsolete”的文件,我们给 rm 加上了 -i 选项,以便在删除每个文件前都先询问你。

3、不区分大小写搜索

你想要在日志文件中不区分大小写地搜索字符串(如“error”),以匹配该字符串的所有出现。用 grep 的 -i 选项忽略大小写,如下所示:

grep -i error logfile.log

不区分大小写的搜索能够找出包含“ERROR”、“error”、“Error”的日志消息,“ErrOR”和“eRrOr”这样的也不例外。该选项在查找大小写混合的单词时尤其管用,或者对于查找的内容无法确定大小时。

4、缩减搜索结果

如果搜索返回的结果不符合预期,其中包括许多并不需要的内容。将结果通过管道传给 grep -v 并用表达式描述出你不想看到的内容。假设你想在日志文件中找出整个 12 月的日志消息。你知道日志文件用字母缩写 Dec 代表 12 月,但不敢肯定总是如此,为了确保找出所有的日志消息,输入下列命令:

grep -i dec logfile

得到的结果却如下所示:

...
error on Jan 01: not a decimal number
error on Feb 13: base converted to Decimal
warning on Mar 22: using only decimal numbers
error on Dec 16 : the actual message you wanted
error on Jan 01: not a decimal number
...

一种快而糙的解决方案是,将第一次得到的结果通过管道传给另一个grep,由后者过滤掉所有的“decimal”。

grep -i dec logfile | grep -vi decimal

将多个 grep 串联在一起(因为前所未见、出乎意料的匹配会不断出现),逐步过滤搜索结果,直至满意,这种做法并不鲜见。

-v 选项非常方便,你只需要记住该排除什么就行了。

5、搜索更复杂的模式

grep 中的正则表达式提供了更为强大的模式匹配功能,能够满足大部分需求。正则表达式描述了待匹配字符串的模式。字母字符(或者对于 shell没有特殊含义的其他字符)只匹配自身。“A”匹配 A,“B”匹配B,这没什么好说的。另一个重要的规则是按位置组合字母,如 AB匹配“AB”。这看起来也是显而易见的。但是,正则表达式还定义了其他一些特殊字符,它们既可以单独使用,也可以与其他字符结合,从而形成更为复杂的模式。

第一个特殊字符是点号(.),它可以匹配任意单个字符。因此,.... 可以匹配任意 4 个字符;A. 匹配“A”以及紧随其后的任意单个字符;.A. 匹配任意单个字符,然后是“A”,接着是任意单个字符(未必和匹配到的第一个字符相同)。

第二个特殊字符时星号(**),匹配上一个字符的 0 次或多次出现,因此,A* 匹配 0 个或多个“A”字符,.* 匹配 0 个或多个任意字符(如“abcdefg”、“aaaabc”、“sdfgf ;lkjhj”,甚至是空行)。

那么 ..* 是什么意思?它匹配任意单个字符以及紧随其后的 0 个或多个任意字符(也就是一个或多个字符,但不能是空行)。

如下所示,我们知道一行的某些单词,我们想模糊匹配,如下操作:

grep -E "1.*22" 2.text  // 匹配1开头,任意个字符后是22

结果如下:

1898090808098822:  

Shell 文件查找

1、查找所有的txt文件

文件系统中到处都是 txt 文件。你想将它们集中到一个位置。那么我们该如何做呢?

find 命令可以找出符合要求的所有文件并执行命令,将其移动到指定位置。例如:

find . -name '*.txt' -print -exec mv '{}'  /txts  \;

find 命令的语法和其他 Unix 命令不同,其选项并不是那种典型的连字符加上单字母,后面再跟上若干参数。find 命令的选项看起来像是简短的单词 1,依照逻辑顺序出现,并描述要查找哪些文件以及如何处理找到的文件(如果存在的话)。这种像单词一样的选项通常称为谓词(predicate)。

find 命令的第一个参数是待搜索的目录。典型用法是用点号(.)代表当前目录,不过你也可以提供一个目录列表,甚至通过指定根目录(/)来搜索整个文件系统(只要权限允许)。

示例中的第一个选项(谓词 -name)指定了要搜索的文件模式。其语法和 bash 的模式匹配语法差不多,因此 *.txt 能够匹配所有以“.txt”结尾的文件名。匹配该模式的文件被认为返回的是真(true),接着将其交给下一个谓词进行处理。

find 会遍历文件系统,将找到的文件名交给谓词测试。如果谓词返回真,就通过。如果返回假,则不再继续往下进行,会接着处理下一个文件名。

谓词 -print 很简单。它总是返回真,同时会将文件名打印到标准输出,因此,能在谓词序列中通过测试而到达这一步的文件都会输出其名称。如果不写,默认会带有这个谓词。

-exec 就有点怪异了。到达这一步的文件名都会变成接下来要执行的命令的一部分。剩下一直到 ; 的这部分就是命令,其中的 {} 会被替换成已查找到的文件名。因此,在上面的例子中,如果 find 在./txt/jazz 子目录中找到名为 1.txt 的文件,那么要执行的命令就会是:

mv ./txt/jazz/1.txt  /txts

所有匹配指定模式的文件都会执行命令。如果找到的文件数量众多,那么命令的执行次数自然也不会少。

2、提升已找到

首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇【多线程与高并发】- 浅谈volatile 下一篇LeetCode刷题第八九十周

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目