小言_互联网的博客

shell学习心得-shell基本介绍跟正则表达式

258人阅读  评论(0)

shell脚本介绍

shell是脚本编程语言,是一门解释型语言,这类程序的执行,是有解释器读入程序代码,并将其转换为内部的形式,在执行。解释器本身就是编译型程序。

我们使用shell编程的主要是因为Linux系统管理需求,通过shell脚本帮助我们自动完成某些工作任务,提升工作效率。


shell程序设计原则

  • 一次做好一件事

进行shell程序编写,要一次就只干好一件事即可,还有其他的功能需要实现,那就把程序以空行进行分开,加上注释,这样可以让程序更清晰,更直观,无论是进行程序设计,编写,调试,测试,维护都是非常方便的。

  • 使用正则表达式

在进行shell脚本编写的时候,发现很多时候,都需要使用正则进行结果匹配,不使用正则的话,会导致结果匹配难度加大,嗯,写好正则准没错。

  • 使用默认的标准输入及输出

在未明确指定文件名的情况下,程序默认会从它的标准输入读取数据,将数据写到它的标准输出,程序错误默认会传送给标准错误输出,使用程序默认的规则既方便自己维护也方便其他同事进行维护,按照标准来,方便你我他。

  • 构建程序结构

写程序之前,应该对程序实现功能进行具体定位,了解当前程序是为了实现什么功能,怎么实现,实现流程等,花个时间,建个大体的程序构建流程。

 

shell编程

  • shell调用

由于现在的Linux系统中有很多shell,那么在shell程序中,shell如何知道我们调用哪个shell,那就在第一行 #!+指定shell路劲即可,在Linux系统中选择默认的/bin/bash即可(选择shell需要满足POSIX标准的才行)

例如:

#!/bin/bahs  

shell基本元素

  • 命令和参数

shell程序最基础的是Linux命令,你对命令很了解,就可以通过shell轻松玩转Linux。

shell识别哪些命令:Linux中只要执行的命令都支持,无论是Linux内建的,shell函数还是外部命令都支持,并且命令执行方式跟你在Linux中执行命令的方式是一样,需要注意的是你在Linux执行命令需要加绝对路劲的话,那在shell脚本一定要加,不然就识别不了,建议不管啥命令都加绝对路劲,还有是只能运行你当前用户所能运行的命令。

# vim wc.sh
 #!/bin/bash
 who | wc -l
# sh wc.sh
2
  • 变量

变量是shell 传递数据的一种方法。变量是用来代表每个值的符号名。我们可以把变量当成一个容器,通过变量,可以在内存中存储数据。也可以在脚本执行中进行修改和访问存储的数据

  • 变量的设置规则:

1、 变量名称通常是大写字母,它可以由数字、字母(大小写)和下划线_组成。变量名区分大小写;但是大家要注意变量名称不能以数字开头

2、 等号= 用于为变量分配值,在使用过程中等号两边不能有空格

3、 变量存储的数据类型是整数值和字符串值

4、 在对变量赋于字符串值时,建议大家用引号将其括起来。因为如果字符串中存在空格隔符号。需要使用单引号或双引号

5、 要对变量进行调用,可以在变量名称前加美元符号$

6、 如果需要增加变量的值,那么可以进行变量值的叠加。不过变量需要用双引号包含“$变量名”或用${变量名}包含

  • 变量的分类

按照变量的作用可以分成 4类:

1、用户自定义变量

2、环境变量:这种中主要保存的是和系统操作相关数据。

3位置参数变量:这种主要是用来向脚本当中传递或据的,名不能自定 义作固的。

4、预定义变量:是 BashBashBash 中已经定义好的变量,名不能自作用也是固。 中已经定义好的变量,名不能自作用也是固。

按照变量作用域可以分成 2类:全局变量和部。

局部变量是 shell shell shell shell 程序内部定义 的,其使用范围仅限于它对不可见。包括:户自程序内部定义 的,其使用范围仅限于它对不可见。包括:户自变量、位置和预定义。

全局变量是环境变量,其值不随 全局变量是环>境,其值不随 shell shell shell shell 脚本的执行结束而消失。


正则表达式

正则表达式是一种匹配模式,通过正则表达式,用户可以精准匹配自己想要的内容。

正则表达式基本是由2个部分组成,分别是一般字符及特殊字符。一般字符是指没有任何意义的字符,也就是说字符没有特殊含义,比如,a,b,c,d等字符;特殊字符是指拥有特殊含义,并且在一定情况下可以转为一般字符那种,也被称为元字符。

正则表达式可以分为基础正则表达式(BRE)扩展正则表达式(ERE)。

  • 基础正则表达式
  • 常见的特殊字符:
BRE/ERE

特别字符

描述(默认以BRE功能为主)

2

$

匹配输入字符串的结尾位置。要匹配$ 字符本身,ERE可以放在任意位置

BRE

( )

标记一个子表达式的开始和结束位置。要匹配这些字符,请使用\( 和\)

2

*

匹配前面的子表达式零次或多次。要匹配* 字符,请使用\*(位于第一个字符就没有任何意义,)

2

+

匹配前面的子表达式一次或多次。要匹配+ 字符,请使用\+

2

.

匹配除换行符\n 之外的任何单字符。要匹配. ,请使用\. ;nul除外

 

[

标记一个中括号表达式的开始。要匹配[,请使用\[

2

?

匹配前面的子表达式零次或一次,或指明一个非贪婪限定符。要匹配? 字符,请使用\?

 

\

将下一个字符标记为或特殊字符、或原义字符、或向后引用、或八进制转义符。例如,'n' 匹配字符'n'。'\n' 匹配换行符。序列'\\' 匹配"\",而'\(' 则匹配"("

2

^

匹配输入字符串的开始位置,除非在方括号表达式中使用,此时它表示不接受该字符集合。要匹配^ 字符本身,请使用\^;ERE置于任何位置都有意义

 

{

标记限定符表达式的开始。要匹配{,请使用\{

2 [...] 方括号表达式,匹配方括号内的任一字符, [a-c],连字符,指的是范围,[^a],^放在方括号里面,则是取反的意思,不匹配里面任一字符
BRE \{n,m\}

区间表达式,匹配它前面单个字符重现的次数。\{n\}指重现n次, \{n,\}至少重现n次,\{n,m\}重现n到m次 ,n与m的值介于0到RE_DUP_MAX之间,centos7中,最大值是32767

# getconf RE_DUP_MAX
32767

BRE \( \) \( "保留空间"\) 主要是存储子表达式,最多可以存储9个
ERE {n,m} 是属于ERE独有的区间表达式
2

|

指明两项之间的一个选择。要匹配|,请使用\|   如:Y | y

 

定位符

 
 

^

匹配输入字符串开始的位置

 

$

匹配输入字符串结尾的位置

 

非打印字符

 
BRE

\s

空格 \s*0个或者多个空格
 

\n

匹配一个换行符

 

\r

匹配一个回车符

 

\t

匹配一个制表符
  • 常见表达式:

# cat wc.sh

matchtouchmkdirnginxmysql

# cat wc.sh | egrep "touch"       #只打印"touch"几个字符,跟常规grep匹配差不多

matchtouchmkdirnginxmysql

# cat wc.sh | egrep "^ma"     #匹配以"ma"字符开头的行

matchtouchmkdirnginxmysql

# cat wc.sh | egrep "mysql$"  #匹配以"mysql"字符结尾的字符,跟命令行中的$差不多

matchtouchmkdirnginxmysql

# cat wc.sh | egrep "^matchtouchmkdirnginxmysql$"  #匹配完整的内容,也就是这一行只能且只有这些内容

matchtouchmkdirnginxmysql 

# cat wc.sh | egrep "[nN]ginx"  #[ ]里面是匹配单个字符,只要满足这个要求,无论是啥字符都行,同时在很多命令中,[ ]里面的内容是可选的

matchtouchmkdirnginxmysql 

# cat wc.sh | egrep "c.m"     #匹配c-m之间的单个字符

matchtouchmkdirnginxmysql

# cat wc.sh | egrep "c.*m"  #匹配c-m之间的0个或者多个字符

matchtouchmkdirnginxmysql

# cat wc.sh | egrep "c.+m" # + 是匹配前面子表达式的1个或者多个字符

matchtouchmkdirnginxmysql

# cat wc.sh | egrep "c.?m"    # ? 匹配前面0个或者1个字符

matchtouchmkdirnginxmysql

  • 常见特殊字符集(在shell里面实践了一下好像跑不了,据说是php的正则表达一种):

  • 基础正则表达式

支持单个字符匹配及多个字符匹配 (用到的字符就是BRE里面的所有标准字符及特殊字符)

 

[ : : ] 字符集,可以把多个字符组合起来成为一个完整的字符串

[ . . ] 排序元素 主要是进行排序

[ = ] 等价字符集,也就2边的字符都是相等的

这几种字符集方式的实现都需要[ ] 来帮忙实现。

 

在 [ ] 中所有字符都会失去其特殊含义。[ * \ . ] 就是字面上的意思,正确写法:[ ] * \ .]

 

  • 分组

分组简单来说是把一串字符串,通过 \( \) 方式形成一个子表达式(单个字符),供后面的正则去匹配,并且最多存储9个子表达式,用数字1-9表示。1个 \( \) 就是一个分组,就是一个整体。

$ cat  ac.txt
hello
helloo
hellooo
hellohel
hellohell
hellohello  

$ cat  ac.txt | grep "hello\{3\}"  #\{n\}在BRE里面是匹配前面单个字符出现的次数
hellooo

$ cat  ac.txt | grep "\(hello\)\{2\}"  
hellohello

#在上面的表里面,有个 \( \) 特殊字符,这里面主要是存放子表达式的,也就是把内容整合为一个整体,
供后面的正则去匹配,简单来说就是把多个字符组合一起,成为单个字符

分组还可以嵌套的:
$ cat  ac.txt  | tail -3
hellohello
queuequeue
queue
$ cat  ac.txt  | grep '\(q\(ue\)\{2\}\)\{2\}'
queuequeue
#这就是个简单的嵌套,也就是这样:\( \( \) \)优先运行里面的\( \) 然后在运行外面最大的\( \)
上面例子解析:
首先运行 q\(ue\)\{2\} 结果是queue,也就是把ue作为一个整体匹配了出现的次数也就是2次
然后运行最外面的 \(queue\)\{2\},结果就是queuequeue,在进行子表达式嵌套的时候会把最里面子
表达的结果给外面的子表达式作为结果输入,跟Linux中的|一个意思。

grep '\(ue\)\{2\}\)' 与 grep '\(ue\{2\}\)' 是有区别的,前者是把ue作为一个字符,后者是把e作为字符
$ cat ac.txt | grep '\(ue\)\{2\}'
queue
$ cat ac.txt | grep '\(ue\{2\}\)'
quee


 

  • 后向引用

$ cat 7.txt
tzc 	word yunying
lij 	word lij
haibing word yunying


需求1:打印tzc那一行
$ cat 7.txt | grep 't.\{2\}\s*word y.\{3,8\}' # . 是表示除\n之外的任意单个字符,这个表示只匹配tzc了
tzc 	word yunying

需求2:匹配word字段周边都相同的行
$ cat 7.txt | grep '\(l.\{2\}\)\s*word \1'  #出现全新玩法 \1
lij 	word lij
注:\1是什么了?这个就是后向引用,也就是\1是引用第一个分组的结果,\( \)这就是分组括号,里面的结果就是分组结果,\1就是匹配第一个分组的结果。
严重强调:\1 \2等等只能匹配\( \)的结果

$ cat  test.txt

abccccabeeee word abccccabeeee

$ cat  test.txt | grep '\(\(abcc.\{2\}\)\ab.\{4\}\) word \2'

abccccabeeee word abccccabeeee

$ cat  test.txt | grep '\(\(abcc.\{2\}\)\ab.\{4\}\) word \1'

abccccabeeee word abccccabeeee

根据上面结果显示,后向引用顺序是由左侧分组符号进行排序的也就是 ((( 分别是\1 \2 \3

后向引用需要以分组为前提的不然就引用不了,后向引用只能引用分组符号 \( \)的匹配结果

\1 表示引用第一个分组括号里面的正则匹配结果,\2 \3依次类推

  • 优先级

    BRE运算符优先级,由高至低

运算符 表示含义
[..] [==] [::] 用于字符排序的方括号符号
\metacharacter 转义的 meta 字符
[ ] 方括号表达式
\( \)   \digit  子表达式与后向引用
*\{   \} 前置单个字符重现的正则表达式
无符号(no symbol) 连续
^  $ 锚点

 

  • 扩展正则表达式

ERE是扩展正则表达式,扩展正则表达式在标准正则表达式上新增一些功能,能满足大家的工作需求。

单个字符匹配跟跟BRE方法是差不多的,但是ERE中的awk里面 \ 有特殊的含义。

  • 反向应用:在通过sed进行扩展正则的时候一样可以使用
  • 字符匹配:ERE在字符匹配方面,与BRE有明显的不同,其中*的功能是一样的。
  • 区间表达式:ERE也存在区间表达式,但是不在是 \{ \},而是以 { } 这种形式展现,且不需要前置 \ 字符。
  • 分组:ERE进行分组的话是 ( ),不需要在加 \ 字符
  • 交替: | 跟BRE方式一样,二选一那种  (read|write) 还有是添加锚点符那种 ^action|active$ 匹配字符串开始处是否有action或者结尾处是否有active     ^(ac|bc)$匹配当前内容里面是否有ac或者bc字符串
  • 优先级:跟BRE是一样的由高到低

  • 额外正则运算表达符

运算符 表示含义
\w 匹配任意单词(可以是单个字符,字符串等等) ac bh ki js n r
\W 匹配任意符号(可以是单个,也可以是多个) ? \ + - == [ ] { } -- ()
\< \> \<ac 匹配以ac开头的字符 df\> 匹配以df结尾的字符  \<qwe\> 那就只匹配qwe字符
\b

单词边界,就是单词和符号之间的边界,单词就是\w匹配的内容,符号是\W匹配的内容,也就是匹配字跟空格之间的一个位置

# cat wc.sh
matCHtouc1223mysl
ac bhmore ki js
jkless

# cat wc.sh  | egrep 's\b'
ac bhmore ki js
jkless

# cat wc.sh  | egrep '\bma'
matCHtouc1223mysl

# cat wc.sh  | egrep '\bac\b'
ac bhmore ki js

总结:通过\b可以匹配开头处的内容及结尾处的内容,至于中间的内容需要\B来匹配

注:更深层次的理解,等我理解完毕再来补充

\B

非单词边界,是单词与单词,符号与符号之间的边界

# cat wc.sh  | egrep '\B1223\B'
matCHtouc1223mysl
# cat wc.sh  | egrep '\B1223'
matCHtouc1223mysl
# cat wc.sh  | egrep '1223\B'
matCHtouc1223mysl

总结:简单来说就是匹配某个内容是否存在

注:更深层次的理解,等我理解完毕再来补充

非常好的正则使用例子:
root@test:/opt/scripts 12:47:52
$ cat hl-ip.txt.bak | sort | awk -F'/' '{print $3,$0}' | sed -r 's/.*\.(\w+).(com|net) /\1.\2 /'| sort -k 1 | awk '{print $2}'
http://10.pic.123456.com/2017-08/mB8CBuXo8u87MFthMmWSEJymrQHS2G5hkgWSAR2q.jpeg
http://1.pic.234567.com/2017-07/FLeGYVYY5EPakINvcORvJvxoR9z19HG2McSuAeww.jpeg

 


 

位置参数

位置参数分别是$0 $1 $2.....$n

# sh system.sh 1 2 3 4

根据上面那个命令展示:$0 就是命令本身 1 是$1 2 是$2 3是$3 依次类推


程序跟踪测试

在Linux命令行:sh -x 叫脚本  #一般都是使用这种方式

在shell脚本里面:以set -x开启跟踪模式  以set -x关闭跟踪模式,例如:

#!/bin/bash
who | wc -l >/dev/null
set -x
if [ $? = 0 ]
then
   echo "zhixingchenggong"
else
   echo "zhixingfailed"
fi
set -x
echo abc

root@test:/opt/scripts/my.scripts 18:52:22
# sh wc.sh
+ '[' 0 = 0 ']'
+ echo zhixingchenggong
zhixingchenggong
+ set -x
+ echo abc
abc

特殊文件

/dev/null 和 /dev/tty

/dev/null 熟称黑洞,将标准输出输出到这个文件后,输出结果会被系统给丢掉,不占用系统任何空间,非常的实用。

/dev/tty  当程序打开此文件时,shell会自动将它重定向到一个实体终端(不怎么用过)


文本输出

echo

printf

printf是模仿C程序库的printf()库里程序,但是功能相当于与echo而言,更复杂,更灵活。printf不支持自动换行,echo支持自动换行

root@test:/opt/scripts/my.scripts 17:45:12
# printf "hello word"
hello wordroot@test:/opt/scripts/my.scripts 17:45:37
# echo "hello word"
hello word
root@test:/opt/scripts/my.scripts 17:47:38
# printf "hello word\n"
hello word
注:根据上图所示,printf不支持换行,需要加\n才行

用法:printf FORMAT [ARGUMENT]...

 


转载:https://blog.csdn.net/yts1115084429/article/details/101998237
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场