Linux/Shell脚本学习笔记【持续更新】

最近在读机械工业出版社的《shell脚本学习指南》,不得不说单纯看书中的语法真的很晦涩难懂,还是结合常见应用场景和案例对比来学习吧!毕竟学也是为了更好的用嘛。

另,这里把学习过程中遇到的一些常见、好用的记录下来,方便以后回顾。毕竟编程语言和框架那么多,程序员是不可能时时刻刻把所有的语法和代码写法记在脑子里滴,知道能靠什么工具实现比较重要。况且在shell命令使用过程中,还有--help来帮忙,能给我们提供比较详尽的介绍。

一、Bash Shell

二、正则表达式 RE

三、Shell命令——文本神器三兄弟 awk,grep,sed

四、其他Shell命令

五、shell例题

六、参考资料



一、Bash Shell

1.bash Shell中的元字符:

bash Shell本身不支持正则表达式,使用正则表达式的是Shell命令和工具,例如grep、awk、sed等。但是bash Shell可以使用正则表达式中的一些元字符实现通配功能。这些元字符在通配中的意义与正则表达式中的意义不完全一致,如下所示;

* 表示——任意位的任意字符,而与前面的字母无关。这里和正则表达式的*对比一下,正则表达式中,*往往用于表达前面一个普通字符的0次或者多次重复。由此可见Shell元字符和正则元字符的不同。

? 表示——一个任意字符^表示——取反[]表示——字母集合(与正则中一样)

{}表示——一组表达式的集合·command·相当于$(command),用于进行命令替换,command为shell命令。(注:·是tab上方的反撇号,在这里编辑出来长得和shell中不同)${variable}相当于$variable,用于进行变量替换,variable表示shell变量。一般来说${variable}和$variable是一样的,只是${variable]在表达变量名的界限时更清晰。除此之外,${variable}还可以用于剪切或取变量的局部等。$[]与$(())用于进行数学计算。

2.管道和重定向:

【用法差异】


管道 —— command 1 | command 2 | command 3 左边的命令有标准输入,右边的命令接受标准输出

它仅能处理经由前面一个指令传出的正确输出信息,也就是 standard output 的信息,对于 stdandard error 信息没有直接处理能力。然后,传递给下一个命令,作为标准的输入 standard input.。

重定向 —— 

command1 < file1 左边的命令需要标准输入,右边只能是文件

command1 > file2 左边的命令有标准输出,右边只能是文件


【进程差异】

管道触发两个子进程执行|两边的程序;

重定向是在一个进程内执行

3.转义符:

转义符可以使得元字符被解析为字面含义,共有三种,反斜杠,双引号,以及单引号。三种的转义程度不尽相同。

' '单引号,不具有变量置换(解析)功能($变为纯文本);硬转义,其内部所有的shell 元字符、通配符都会被关掉。

" " 双引号,具有变量置换(解析)功能($可保留相关功能);软转义,其内部只允许出现特定的shell 元字符

\跳脱字符,将特殊字符或者通配符还原成一般字符

3.1 反斜杠 \ ——去除其后紧跟的元字符或通配符的特殊意义。

3.2 双引号 "" ——又称软转义,其内部只允许出现特定的shell 元字符

3.3 单引号 ‘ ’ ——又称硬转义,其内部所有的shell 元字符、通配符都会被关掉。注意,硬转义中不允许出现单引号。

二、正则表达式RE 

1.正则表达式的元字符:

这一小节着重讲解正则表达式,因为正则表达式是UNIX工具使用和构建模型上的基础,值得花时间学习并在练习中不断熟悉它。

正则表达式区分BRE以及ERE共两种模式,正则表达式由一般字符和元字符组成。BRE和ERE的元字符稍有不同,如下所示:

【BRE】&【ERE】共享的元字符:

\——用于关闭后续字符的特殊意义。或者用\{...\}

*——用于匹配前面一个普通字符的0次或者多次重复。对于ERE来说,*的前置字符可以是正则表达式,例如.*带表“匹配任一字符的任意长度”

.——用于匹配任意单个字符

^——表示匹配紧接着的正则表达式。(文本匹配锚点)

$——匹配前面的正则表达式。(文本匹配锚点)

[]——匹配方括号内的任一字符。


【BRE】

\{n\}——匹配前面字符出现n次,如[a-z]\{5\}表示精确匹配5个小写英文字母

\{n,\}——匹配前面字符至少出现n次

\{n,m\}——区间表达式。匹配前面字符出现n--m次

\(  \)...\n —— \(与\)之间的模式存储在特殊的保留空间,最多可以将9个独立的自模式存储在单个模式中。子模式可通过转义序列\1至\9,被重复使用在相同模式中,\n指的是“匹配于第n个先前方括号内子表达式匹配成功的字符”。如\(ab\).*\1指的是匹配于ab组合的两次重现,中间可存在任何数目的字符。如\(ab\)\(cd\)[def]*\2\1表达的是abcd...cdab,中间可以是def字符集合的任意组合,故可以匹配的最小字符串是abcdcdab,还可以匹配abcdeeecdab,abcdddeeffcdab。这种机制是BRE提供的后向引用机制,指的是“匹配于正则表达式匹配的先前的部分”。在ERE里,\(..\)不表示后向引用,匹配的是字面上的左括号和右括号。

【ERE】—— 正则表达式的扩展

{}——区间表达式,表示匹配前面的单个字符重现的次数区间。不需要反斜杠。

? ——匹配?之前的正则表达式0次或者1次,如JO?B可以匹配JOB,JOOB

+ ——匹配+之前的正则表达式1次或者多次,如S+EU可以匹配SSEU,SSSEU等,但不可以表示SEU因为此处的+至少匹配一个S

|——表示或者,匹配|之前或者之后的正则表达式

【正则表达式的扩展】

\<  \>分别匹配单词word的开头和结尾。例如/可以匹配eat a lambchop而不能匹配 use chopsticks, /则既无法匹配use chopsticks又无法匹配eat a lambchop

【UNIX程序及其正则表达式类型】

grep: BRE,\<  \>

sed: BRE,\<  \>

ed: BRE,\<  \>

ex/vi: BRE,\<  \>

more: BRE,\<  \>

egrep:ERE

awk:ERE

lex:ERE

记住我们的Linux三剑客,sed, awk,grep,他们所支持的正则是不同的哦。

注意:横杠字符“-”虽然不是正则表达式的元字符,但由于横杆字符是引出命令选项的特殊字符,所以需要用引号和转义符来表示。例如,想要在1.txt文件中找到以“-----”连续五个横杠符号开头的字符串,应该使用以下的命令

grep "\-\{5\}" 1.txt

那么“-----”可不可以呢?答案是不可以。无论你是用"\-\{5\}"还是"\-\-\-\-\-"来表示连续5个“-”,反斜杠转义符都是少不了的。预知原因为何,请看第3小点转义符中相关说明。



三、Shell命令——文本神器三兄弟 awk,grep,sed

grep

grep家族有三兄弟:grep , fgrep , egrep

grep: 标准

egrep:扩展grep命令,支持正则表达式(基本和扩展),等价于grep -E

fgrep:快速grep命令,不支持正则表达式,按照字符串的字面意思进行匹配,等价于grep -F

一般来说,egrep和fgrep极少使用

awk

awk是一种能对结构化数据进行操作,并产生格式化报表的工具

sed

非交互式文本编辑器,可对文本文件和标准输入(键盘输入、文件重定向、字符串、变量or来自管道的文本)进行编辑(输出、插入、删除、替换等)

sed只是对缓冲区中原始文件的副本进行编辑,不编辑原本的文件

sed调用方式

(1)在Shell命令行输入命令调用sed:

sed 'sed-command' input-file>result-file 

(2)将sed命令插入脚本文件之后,通过sed命令调用它

sed -f sed脚本文件 input-file

-f表示正在调用sed脚本文件

(3)将sed命令插入脚本文件之后,设置该脚本文件为可执行,然后直接执行该脚本。(这种方式的sed脚本文件需要以sha-bang(#!)开头)

./sed脚本文件 input-file

sed命令的组成

一般由定位文本行和sed编辑命令(可以放在单引号内或者单引号外)两部分组成,sed提供两种方式定位文本:

(a)使用行号,指定一行,或者指定行号范围

(b)使用正则表达式

sed编程的栗子



四、其他Shell命令

1. find

2.sort 排序

3.uniq 去重【sort和uniq经常配套使用,毕竟生活中许多统计场景都需要去重、排序、统计频率等操作】

4.head和tail

比较常见的用法是head -n file.txt和tail -n file.txt,用于取file.txt文件的前n行和后n行

次常见且比较灵巧的用法还有 head -n-10 file.txt和tail -n+10 file.txt等

前者代表除了最后10行数据之外,显示其余所有内容。【排除后十行】

后者代表从文本文件第10行开始,取其后部。【从第十行开始】


五、Shell例题

【例1】习题:leetcode 195 《第十行》

给定一个文本文件 file.txt,请只打印这个文件中的第十行。

示例:

假设 file.txt 有如下内容:

Line 1

Line 2

Line 3

Line 4

Line 5

Line 6

Line 7

Line 8

Line 9

Line 10

你的脚本应当显示第十行:Line 10

链接:https://leetcode-cn.com/problems/tenth-line

方法一:借用python (比较trick的一个写法,适合shell救急)

方法二:head tail大法好

对于tail和head的使用,有两种思路:

一种是取前十行的最后一行head -10 file.txt|tail -1,这种思路需要考虑文件的实际行数

若超过十行,则可直接取最后一行,即为第十行( head+tail 夹逼法)

若不超过十行,直接对head -10 file.txt做tail操作实际上取到的是第6、7、8、9行(视file.txt实际行数而定)

另一种是取从第十行开始的内容,取其第一行。这种思路无需对总行数小于10的情况做检验,会自动返回空字符串,符合题目要求。

tail -n+10 file.txt|head -1

方法三:巧用awk sed


摘抄力扣大佬答案

-n选项表示:不打印sed编辑对象的全部内容

【例2】

grep "([0-9]\{3\})" number.txt 不含转义标志"\","("与")"直接匹配中字符串"(234)"中的双括号

grep "\([0-9]\{3\}\)" number.txt 含转义字符,不参与字符匹配

练习题:详见leetcode 193 有效电话号码

六、参考资料


1、Leetcode    https://leetcode-cn.com/

2、OSCHINA    https://my.oschina.net/badboy2/blog/478953

3、 《Shell脚本学习指南》机械工业出版社

你可能感兴趣的:(Linux/Shell脚本学习笔记【持续更新】)