超级详细的 shell编程知识讲解 —— 第二部分(全文3万多字,看完之后不想成为高手也难!)


这里是一段防爬虫文本,请读者忽略。
本文原创首发于CSDN,作者IDYS
博客首页:https://blog.csdn.net/weixin_41633902/
本文链接:https://blog.csdn.net/weixin_41633902/article/details/108453404
未经授权,禁止转载!恶意转载,后果自负!尊重原创,远离剽窃!


写在开头的话

  • 请记住:实践是掌握知识的最快方法
  • 如果你只是怀着看看的态度去快速浏览文章,而不去认认真真的把文章里面讲的任何一个知识点去实践一遍,那么你永远也掌握不了它
  • 生命不息,折腾不止!

shell 编程进阶

00. 正则表达式

0.1 概述

  • 正则表达式和通配符的区别:正则表达式用来在文件中匹配符合条件的 字符串,通配符用来匹配符合条件的文件名。其实这种区别只在Shell 当中适用,因为用来在文件当中搜索字符串的命令,如grepawksed等命令可以支持正则表达式,而在系统当中搜索文件的命令,如 lsfindcp 这些命令不支持正则表达式,所以只能使用 shell 自己的通配符来进行匹 配了。

0.2 基础正则表达式

元字符作用
*前一个字符匹配0 次或任意多次
.匹配除了换行符外任意一个字符
^匹配行首。例如:^hello 会匹配以 hello 开头的行
$匹配行尾。例如:hello&会匹配以 hello 结尾的行
[^]匹配除中括号的字符以外的任意一个字符。例如:[^0-9]匹配任意 一位非数字字符,[^a-z]表示任意一位非小写字母。
\转义符。用于取消。将特殊符号的含义取消。
\{n\}表示其前面的字符恰好出现 n 次。例如:[0-9]\{4\} 匹配 4 位数字, [1][3-8][0-9]\{9\} 匹配手机号码。
\{n,\}表示其前面的字符出现不小于 n 次。例如: [0-9]\{2,\} 表示两位及以上的数字。
\{n,m\}表示其前面的字符至少出现n次,最多出现m次。例如:[a-z]\{6,8\} 匹配 6 到 8 位的小写字母。
  • Linux正则表达式分为基础正则表达式扩展正则表达式grep只支持基础正则表达式,grep -E支持扩展正则表达式,egrep支持扩展正则表达式

  • 设置grep可以显示颜色
[root@idys1 ~]# vim ~/.bashrc 
alias grep='grep --color=auto'
[root@idys1 ~]# source .bashrc  # 使其生效

# 为了演示方便,我修改命令提示符变量 PS1
[root@idys1 ~]# echo $PS1
[\u@\h \W]\$
[root@idys1 ~]# vim /etc/profile
[root@idys1 ~]# source /etc/profile
your UID=0 your home=/root 


  • 建立练习文本
[dayuanshuai@idys1 day5] vim my_task_file.txt
  1 Mr. Li idys said:
  2 he was the most honest man.
  3 123despise him.
  4 But since Mr. linus towards came,
  5 he never saaaid those words.
  6 5555nice!
  7 because,actuaaaally,
  8 Mr. idys Linus is the most honest man
  9 Later,Mr. Li idys soid his hot body
 10 and every think it is so fun.
 11 there is worthy to see

  1. *前一个字符匹配 0 次,或任意多次
  • 匹配文本中含有a的行
[dayuanshuai@idys1 day5] grep a my_task_file.txt 
Mr. Li idys said:
he was the most honest man.
But since Mr. linus towards came,
he never saaaid those words.
because,actuaaaally,
no one saaid he is honest
Mr. idys Linus is the most honest man
Later,Mr. Li idys soid his hot body
and every think it is so fun.
  • 匹配文本中含有sid之间至少有两个a的行
[dayuanshuai@idys1 day5] grep 'sa\{2,\}id' my_task_file.txt    
he never saaaid those words.
no one saaid he is honest

# 以下也可以
[dayuanshuai@idys1 day5] grep saaa*id my_task_file.txt 
he never saaaid those words.
no one saaid he is honest

  1. . 匹配除了换行符外任意一个字符
  • 正则表达式.只能匹配一个字符,这个字符可以是任意字符
[dayuanshuai@idys1 day5] grep s..d my_task_file.txt 
Mr. Li idys said:
Later,Mr. Li idys soid his hot body

通配符中*代表任意的长度的所有字符,?代表单个字符

  • 匹配所有字符
[dayuanshuai@idys1 day5] grep ".*" my_task_file.txt 
Mr. Li idys said:
he was the most honest man.
123despise him.
But since Mr. linus towards came,
he never saaaid those words.
5555nice!
because,actuaaaally,
no one saaid he is honest
Mr. idys Linus is the most honest man
Later,Mr. Li idys soid his hot body
and every think it is so fun.
there is worthy to see

  1. ^匹配行首,$匹配行尾
  • 匹配以M开头的行
[dayuanshuai@idys1 day5] grep "^M" my_task_file.txt  
Mr. Li idys said:
Mr. idys Linus is the most honest man
  • 匹配以n结尾的行
[dayuanshuai@idys1 day5] grep "n$" my_task_file.txt 
Mr. idys Linus is the most honest man
  • 删除行首空格
[dayuanshuai@idys1 day5] cat my_task_file.txt 
Mr. Li idys said:
he was the most honest man.
123despise him.
But since Mr. linus towards came,
he never saaaid those words.
5555nice!
because,actuaaaally,
no one saaid he is honest
Mr. idys Linus is the most honest man
Later,Mr. Li idys soid his hot body
and every think it is so fun.
there is worthy to see
  22222
 1111
           03423


[dayuanshuai@idys1 day5] sed  -r 's/^[[:space:]]+//g' my_task_file.txt 
Mr. Li idys said:
he was the most honest man.
123despise him.
But since Mr. linus towards came,
he never saaaid those words.
5555nice!
because,actuaaaally,
no one saaid he is honest
Mr. idys Linus is the most honest man
Later,Mr. Li idys soid his hot body
and every think it is so fun.
there is worthy to see
22222
1111
03423
  • 删除行首的#和空格
[dayuanshuai@idys1 day5] cat my_task_file.txt 
Mr. Li idys said:
he was the most honest man.
123despise him.
But since Mr. linus towards came,
he never saaaid those words.
5555nice!
because,actuaaaally,
no one saaid he is honest
Mr. idys Linus is the most honest man
Later,Mr. Li idys soid his hot body
and every think it is so fun.
there is worthy to see
  22222
 1111
           03423
#  dwdsd
#   awda
# #   #   sefr

[dayuanshuai@idys1 day5] sed -r "s/^[#,[:space:]]+//g" my_task_file.txt 
Mr. Li idys said:
he was the most honest man.
123despise him.
But since Mr. linus towards came,
he never saaaid those words.
5555nice!
because,actuaaaally,
no one saaid he is honest
Mr. idys Linus is the most honest man
Later,Mr. Li idys soid his hot body
and every think it is so fun.
there is worthy to see
22222
1111
03423
dwdsd
awda
sefr
  • 匹配空号,并且显示行号
[dayuanshuai@idys1 day5] grep -n '^$' my_task_file.txt 
19:
20:
  • grep -v 表示对匹配到的字符取反,查找非空白行,(含有空格的行,也为空白行)
[dayuanshuai@idys1 day5] cat -n my_task_file.txt                       
     1  Mr. Li idys said:
     2  he was the most honest man.
     3  123despise him.
     4  But since Mr. linus towards came,
     5  he never saaaid those words.
     6  5555nice!
     7  because,actuaaaally,
     8  no one saaid he is honest
     9  Mr. idys Linus is the most honest man
    10  Later,Mr. Li idys soid his hot body
    11  and every think it is so fun.
    12  there is worthy to see
    13    22222
    14   1111
    15             03423
    16  #  dwdsd
    17  #   awda
    18  # #   #   sefr
    19     
    20      
    21      
    22      
    23  lll  

[dayuanshuai@idys1 day5] grep -nv "^[[:space:]]*$" my_task_file.txt 
1:Mr. Li idys said:
2:he was the most honest man.
3:123despise him.
4:But since Mr. linus towards came,
5:he never saaaid those words.
6:5555nice!
7:because,actuaaaally,
8:no one saaid he is honest
9:Mr. idys Linus is the most honest man
10:Later,Mr. Li idys soid his hot body
11:and every think it is so fun.
12:there is worthy to see
13:  22222
14: 1111
15:           03423
16:#  dwdsd
17:#   awda
18:# #   #   sefr
23:lll 

.不会匹配空白行,但是会匹配空格


  1. [] 匹配中括号中指定的任意一个字符,只匹配一个字符
  • []会匹配中括号中指定任意一个字符,注意只能匹配一个字符。比如[ao]中要么会匹配一个 a 字符,要不会匹配一个 o 字符:
[dayuanshuai@idys1 day5] grep "s[ao]id" my_task_file.txt 
Mr. Li idys said:
Later,Mr. Li idys soid his hot body
  • 如果我们在[ao]后面加入*号呢?那么它就会变为0个到任意个ao的组合方式
[dayuanshuai@idys1 day5] grep "s[ao]*id" my_task_file.txt 
Mr. Li idys said:
he never saaaid those words.
no one saaid he is honest
Later,Mr. Li idys soid his hot body
saoid
soaid
soooid
saaaid
saooaoaid
sid   # 即使s 和 id中,没有任意一个字符也会匹配

  1. [^] 匹配除中括号的字符以外的任意一个字符
  • 匹配含有任意个数字和空格的组合
[dayuanshuai@idys1 day5] grep -E "^[[:digit:][:space:]]*$" my_task_file.txt 
  22222
 1111
           03423
   
    
    
   
  • 匹配含有非数字的行
[dayuanshuai@idys1 day5] grep "^[^0-9]*$" my_task_file.txt 
Mr. Li idys said:
he was the most honest man.
But since Mr. linus towards came,
he never saaaid those words.
because,actuaaaally,
no one saaid he is honest
Mr. idys Linus is the most honest man
Later,Mr. Li idys soid his hot body
and every think it is so fun.
there is worthy to see
saaaoooaoao
saoid
soaid
soooid
saaaid
saooaoaid
sid
#  dwdsd
#   awda
# #   #   sefr
   
    
    
    
lll 
  • 匹配没有小写字母的行,并且该行没有空格
[dayuanshuai@idys1 day5] cat my_task_file.txt 
Mr. Li idys said:
he was the most honest man.
123despise him.
But since Mr. linus towards came,
he never saaaid those words.
5555nice!
because,actuaaaally,
no one saaid he is honest
Mr. idys Linus is the most honest man
Later,Mr. Li idys soid his hot body
and every think it is so fun.
there is worthy to see
saaaoooaoao
saoid
soaid
soooid
saaaid
saooaoaid
sid
  22222
 1111
           03423
#  dwdsd
#   awda
# #   #   sefr
   
123   
    
    
lll  
123

[dayuanshuai@idys1 day5] grep -nE '^[^a-z]+$' my_task_file.txt | grep -vE "[[:space:]]+"
31:123
  1. \ 转义符
  • 匹配以.结尾的行
[dayuanshuai@idys1 day5] grep "\.$" my_task_file.txt 
he was the most honest man.
123despise him.
he never saaaid those words.
and every think it is so fun.
  • 匹配包含三个连续的数字,超过3个连续的数字,不能匹配
[dayuanshuai@idys1 day5] grep "[[:digit:]]\{3\}[^[:digit:]]" my_task_file.txt   
123despise him.
5555nice!
123 

  1. \{n\}表示其前面的字符恰好出现 n
  • 查找中间只含有3个a的行,中间多一个a也不行
[dayuanshuai@idys1 day5] grep 'a\{3\}' my_task_file.txt   
# 按照这种方式就会看到4个连续a的情况
he never saaaid those words.
because,actuaaaally,   # 含有4个连续的a
saaaoooaoao
saaaid

[dayuanshuai@idys1 day5] grep '[^a]a\{3\}[^a]' 
# 这种方式的话就会看到只含有3个连续a的情况,多一个a也不符合
my_task_file.txt 
he never saaaid those words.
saaaoooaoao
saaaid


  • 查找4个连续的a或者4个以上连续的a的行
[dayuanshuai@idys1 day5] grep 'a\{4,\}' my_task_file.txt   
because,actuaaaally,
  • 将行中连续的3个数字过滤出来显示。连续数字超过3个的则不显示
# 先过滤出 只含有三个连续数字的行
[dayuanshuai@idys1 day5] grep -E "[^[:digit:]][[:digit:]]{3}[^[:digit:]]|^[[:digit:]]{3}[^[:digit:]]|[^[:digit:]][[:digit:]]{3}$" my_task_file.txt
123despise him.
my123dddand456dd
123

# 然后再将3个数字提炼出来
[dayuanshuai@idys1 day5] grep -E "[^[:digit:]][[:digit:]]{3}[^[:digit:]]|^[[:digit:]]{3}[^[:digit:]]|[^[:digit:]][[:digit:]]{3}$" my_task_file.txt | grep -oE '[[:digit:]]{3}' 
123
123
456
123

  1. \{n,\}表示其前面的字符出现不小于 n
  • 查找连续3次及其以上的数字
[dayuanshuai@idys1 day5] grep -o "[[:digit:]]\{3,\}" my_task_file.txt
123
5555
123
456
22222
1111
03423
123
123

  1. \{n,m\}匹配其前面的字符至少出现 n 次,最多出现 m
  • 匹配最少两位数,最多三位数的数字
[dayuanshuai@idys1 day5] grep -o "[[:digit:]]\{2,3\}" my_task_file.txt 
123
555
123
456
222
22
111
034
23
123
123

0.3 扩展正则表达式

  • 正则表达式中还可以支持一些元字符,比如+?|()

  • 其实 Linux 是支持这些元字符的,只是 grep 命令默认不支持而已。如果要想支持这些元字符,必须使用 egrep 命令或 grep -E 选项,所以我们又把这些元字符称作扩展元字符。

  • 如果查询 grep 的帮助,对 egrep 的说明就是和 grep -E 选项一样的命令,所以我们可以把两个命令当做别名来对待

扩展元字符作用
+前一个字符匹配 1 次或任意多次。 如“go+gle”会匹配goglegooglegooogle,当然如果o有更多个,也能匹配。
?前一个字符匹配 0 次或 1 次。如colou?r可以匹配colourcolor
|匹配两个或多个分支选择。 如was|his会匹配既包含was的行,也匹配包含his的行
()匹配其整体为一个字符,即模式单元。可以理解为由多个单个字符组成的大字符。 如“(dog)+”会匹配dogdogdogdogdogdog等,因为被()包含的字符会当成一个整体。但hello (world | earth) 会匹配hello worldhello earth

  • 匹配邮箱
[dayuanshuai@idys1 day5] cat email.txt 
123@126.com
123@126.comcomcom
23423asdsz@ass21.com
asdas@sdfs.sdfs
sdfsd@sdfsd.sdfsd
[dayuanshuai@idys1 day5] grep -E "[[:alnum:]]+@[[:alnum:]]+\.com$" email.txt
123@126.com
23423asdsz@ass21.com
  • 匹配IP地址,非法IP地址不匹配
[dayuanshuai@idys1 day5] cat new_ip.txt 
123.45.12.123wq
q123.12.1.1c
1233.1234.1.12c
12.12.123.12
  1.1.2.3 
12.1.212.1.5
1.0.0.0
0.0.0.0
127.12.0.0
12.12.124.123.231.123
192.168.1.0

[dayuanshuai@idys1 day5] grep -Eo "^((\b[1-9]\b|\b[1-9][0-9]\b|\b1[0-9]{2}\b|\b2[0-4][0-9]\b|\b25[0-5]\b)\.){1}((\b[1-9]\b|\b[1-9]?[0-9]\b|\b1[0-9]{2}\b|\b2[0-4][0-9]\b|\b25[0-5]\b)\.){2}(\b[1-9]\b|\b[1-9]?[0-9]\b|\b1[0-9]{2}\b|\b2[0-4][0-9]\b|\b25[0-4]\b){1}$" new_ip.txt | grep -vE "[[:digit:]]+.0.0.0|[[:digit:]]+.[[:digit:]]+.0.0"       
12.12.123.12
192.168.1.0

01.字符截取和替换命令

1.1 cut 列提取命令

  • 格式:
    • cut [选项] 文件名
  • 选项:
    • -f 列号:提取第几列
    • -d 分隔符:按照指定分隔符分割列
    • -c 字符范围:不依赖分隔符来区分列,而是通过字符范(行首为 0)来进行字段提取。n-表示从第 n 个字符到行尾;n-m从第 n 个字符到第 m 个字符;-m表示从第 1 个字符到第m 个字符。

cut 命令的默认分隔符是制表符,也就是tab键,不过对空格符可是支持的不怎么好啊。我们先建立一个测试文件,然后看看cut命令的作用吧:

  • 将文本里面的空格全部替换为TAB
# 首先 创造一个文本,这个时候,字符的显示格式是不对齐
[dayuanshuai@idys1 cut_dir] vim student_new.txt
  1 ID Name gender Mark
  2 1 Liming M 86
  3 2 Sc M 90
  4 3 Tg M 83
# 将空格替换为字符串
[dayuanshuai@idys1 cut_dir] sed -i "s/\ /\t/g" student_new.txt

# 再次查看文本,发现文本对齐了
[dayuanshuai@idys1 cut_dir] cat student_new.txt 
ID      Name    gender  Mark
1       Liming  M       86
2       Sc      M       90
3       Tg      M       83
  • 提取出所有人的名字
[dayuanshuai@idys1 cut_dir] sed '1d' student_new.txt | cut -f 2
Liming
Sc
Tg
  • 提取名字和性别 并且以 : 作为分隔符
[dayuanshuai@idys1 cut_dir] sed "1d" student_new.txt | awk 'BEGIN{IFS="\t"}{print $1":"$2}'
1:Liming
2:Sc
3:Tg
  • 提取出第二行人名字的姓氏
[dayuanshuai@idys1 cut_dir] head -2 student_new.txt | tail -1 | cut -c 3-4
Li
  • 提取出普通用户的用户名
[dayuanshuai@idys1 cut_dir] grep -E ":\b[5-9][0-9][0-9]\b:" /etc/passwd | cut -d ":" -f 1
dayuanshuai
xiao
hadoop
test2
peiqi
  • 想用 cut 命令截取 df 命令的第一列和第三列
# 首先查看内容
[dayuanshuai@idys1 cut_dir] df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda3        27G  3.3G   22G  14% /
tmpfs           931M     0  931M   0% /dev/shm
/dev/sda1       190M   36M  145M  20% /boot
/dev/sdb1        14M  139K   13M   2% /data
[dayuanshuai@idys1 cut_dir] df -h | sed -r "s/[[:space:]]+/ /g" | cut -d " " -f 1,3
Filesystem Used
/dev/sda3 3.3G
tmpfs 0
/dev/sda1 36M
/dev/sdb1 139K

1.2 awk编程

  • printf格式化输出

  • 使用形式

    • printf  输出类型输出格式 输出内容
  • 输出类型:

输出类型含义
%s输出字符串。n 是数字指代输出几个字符
%ni输出整数。n 是数字指代输出几个数字
%m.nf输出浮点数。mn 是数字,指代输出的整数位数和小数位数。如%8.2f代表共输出 8 位数,其中 2 位是小数,6 位是整数。
  • 输出格式
输出格式含义
\a输出警告声音
\b输出退格键,也就是 Backspace
\f清除屏幕
\n换行
\r回车,也就是 Enter
\t水平输出退格键,也就是 Tab
v垂直输出退格键,也就是 Tab 键

  • 创建一个文件,名为student_me.txt
# 可以看到文件没有对齐等
[dayuanshuai@idys1 cut_dir] vim student_me.txt
  1 ID Name PHP Linux MySQL Average
  2 1 idys 82  95 86 87.66
  3 2 fool  74 96 87 85.66
  4 3 itrh   99 83 93 91.66

# 将所有的空格替换为,制表符
[dayuanshuai@idys1 cut_dir] sed -ri 's/[[:space:]]+/\t/g' student_me.txt

# 再次查看文件,内容对齐
[dayuanshuai@idys1 cut_dir] cat student_me.txt 
ID      Name    PHP     Linux   MySQL   Average
1       idys    82      95      86      87.66
2       fool    74      96      87      85.66
3       itrh    99      83      93      91.66
  • printf输出文件内容
[dayuanshuai@idys1 cut_dir] printf "%s" $(cat student_me.txt)
IDNamePHPLinuxMySQLAverage1idys82958687.662fool74968785.663itrh99839391.66[dayuanshuai@idys1 cut_dir] printf "%s" `cat student_me.txt`
IDNamePHPLinuxMySQLAverage1idys82958687.662fool74968785.663itrh99839391.66[dayuanshuai@idys1 cut_dir] 

可以看到printf直接将文件内容全部输出,而没有进行换行,对齐等操作

  • 使用%s代表输出类型,\t指代输出格式
[dayuanshuai@idys1 cut_dir] printf "%s\t%s\t%s\t%s\t%s\t%s\n" $(cat student_me.txt)
ID      Name    PHP     Linux   MySQL   Average
1       idys    82      95      86      87.66
2       fool    74      96      87      85.66
3       itrh    99      83      93      91.66
  • 如果希望下面的数字显示为浮点数的形式,那么怎么表示呢?使用m.n%表示即可
[dayuanshuai@idys1 cut_dir] printf "%s\t%s\t%s\t%s\t%s\t%s\n" `head -1 student_me.txt` ;printf "%3.1f\t%s\t%3.1f\t%3.1f\t%3.1f\t%3.1f\n" `sed '1d' student_me.txt`           
ID      Name    PHP     Linux   MySQL   Average
1.0     idys    82.0    95.0    86.0    87.7
2.0     fool    74.0    96.0    87.0    85.7
3.0     itrh    99.0    83.0    93.0    91.7

  • awk 基本使用

  • 使用格式

    • awk  条件 1{动作 1} 条件 2{动作 2}…  文件名
  • 条件(pattern)

    • 一般使用关系表达式作为条件。这些关系表达式非常多
表达式含义
x > 10判断变量 x 是否大于 10
x == y判断变量 x 是否等于变量 y
A ~ B判断字符串 A 中是否包含能匹配 B 表达式的子字符串
A !~ B判断字符串 A 中是否不包含能匹配 B 表达式的子字符串
  • 动作(Action)
    • 格式化输出
    • 流程控制语句

  • 格式化输出的用法与演示

  • 提取出df -h显示的第1列和第3列,不显示第一行

# 先查看df -h的输出结果
[dayuanshuai@idys1 cut_dir] df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda3        27G  3.3G   22G  14% /
tmpfs           931M     0  931M   0% /dev/shm
/dev/sda1       190M   36M  145M  20% /boot
/dev/sdb1        14M  139K   13M   2% /data

# 不显示第一行查看第1列和第三列
[dayuanshuai@idys1 cut_dir] df -h | awk '{ if(NR>1) printf $1"\t"$3"\n"}'
/dev/sda3       3.3G
tmpfs   0
/dev/sda1       36M
/dev/sdb1       139K

# 换种方式写
[dayuanshuai@idys1 cut_dir] df -h | awk 'NR>1{printf $1"\t"$3"\n"}' 
/dev/sda3       3.3G
tmpfs   0
/dev/sda1       36M
/dev/sdb1       139K
  • 显示出磁盘使用量大于10%的行
# 首先查看磁盘使用量
[dayuanshuai@idys1 cut_dir] df -h
Filesystem      Size  Used Avail Use% Mounted on
/dev/sda3        27G  3.3G   22G  14% /
tmpfs           931M     0  931M   0% /dev/shm
/dev/sda1       190M   36M  145M  20% /boot
/dev/sdb1        14M  139K   13M   2% /data

# 显示出使用量大于 10%的磁盘
[dayuanshuai@idys1 cut_dir] df -h | sed -r "1,\$s/%//g" | awk 'NR>1{if($5>10)print $1"\t"$2"\t"$3"\t"$4"\t"$5"%""\t"$6}' | sed "1i`df -h | head -1`" | sed -r 's/[[:space:]]+/\t/g'
Filesystem      Size    Used    Avail   Use%    Mounted on
/dev/sda3       27G     3.3G    22G     14%     /
/dev/sda1       190M    36M     145M    20%     /boot

  • awk条件
条件的类型条件说明
awk保留字BEGINawk 程序一开始时,尚未读取任何数据之前执行。BEGIN 后的动作只在程序开始时执行一次
awk保留字ENDawk程序处理完所有数据,即将结束时执行。END 后的动作只在程序结束时执行一次
关系运算符>大于
关系运算符<小于
关系运算符>=大于等于
关系运算符<=小于等于
关系运算符==等于。用于判断两个值是否相等,如果是给变量赋值,请使用 =
关系运算符!=不等于
关系运算符A~B判断字符串 A 中是否包含能匹配 B表达式的子字符串
关系运算符A!~B判断字符串 A 中是否不包含能匹配 B 表达式的子字符串
正则表达式/正则/如果在//中可以写入字符,也可以支持正则表达式

  • BEGIN

    • BEGINawk 的保留字,是一种特殊的条件类型。BEGIN的执行时机是在 awk 程序一开始时, 尚未读取任何数据之前执行。一旦 BEGIN 后的动作执行一次,当 awk 开始从文件中读入数据,BEGIN 的条件就不再成立,所以 BEGIN 定义的动作只能被执行一次。
  • 演示

[dayuanshuai@idys1 cut_dir] df -h | awk 'BEGIN{print "============================"} END{print "============================"}  {print $1"\t"$2$3$4$5}'  
============================
Filesystem      SizeUsedAvailUse%
/dev/sda3       27G3.3G22G14%
tmpfs   931M0931M0%
/dev/sda1       190M36M145M20%
/dev/sdb1       14M139K13M2%
============================
# 这里定义了两个动作
# 第一个动作使用 BEGIN 条件,所以会在读入文件数据前打印“====================”(只会执行一次)
#这里定义了两个动作
#第二个动作会打印文件1,2,3,4,5列字段
  • END
    • END 也是 awk 保留字,不过刚好和 BEGIN 相反。END 是在awk 程序处理完所有数据,即将结束时执行。END 后的动作只在程序结束时执行一次。例如:

  • 关系运算符

  • 查看平均成绩大于87的学生的姓名

# 首先查看文件内容
[dayuanshuai@idys1 cut_dir] cat student_me.txt 
ID      Name    PHP     Linux   MySQL   Average
1       idys    82      95      86      87.66
2       fool    74      96      87      85.66
3       itrh    99      83      93      91.66

# 执行题目要求操作,打印出平均分大于 87的学生的姓名
[dayuanshuai@idys1 cut_dir] cat student_me.txt | awk 'NR>1{if($5>87) print $2}'
itrh

加入了条件之后,只有条件成立动作才会执行,如果条件不满足,则动作则不运行。通过这个实 验,大家可以发现,虽然 awk是列提取命令,但是也要按行来读入的。这个命令的执行过程是这样的

  1. 如果有 BEGIN 条件,则先执行 BEGIN 定义的动作

  2. 如果没有 BEGIN 条件,则读入第一行,把第一行的数据依次赋予$0$1$2 等变量。其中$0代表此行的整体数据,$1代表第一字段,$2 代表第二字段

  3. 依据条件类型判断动作是否执行。如果条件符合,则执行动作,否则读入下一行数据。如果没有条件,则每行都执行动作

  4. 读入下一行数据,重复执行以上步骤

  • 查看idys的平均成绩
[dayuanshuai@idys1 cut_dir] cat student_me.txt | awk 'NR>1{if($2 ~ /idys/) print $6}'
87.66

这里要注意在 awk 中,使用//包含的字符串,awk 命令才会查找。也就是说字符串必须用// 包含,awk 命令才能正确识别

  • 查找以66结尾的行
[dayuanshuai@idys1 cut_dir] awk ' /66$/ {print}' student_me.txt      
1       idys    82      95      86      87.66
2       fool    74      96      87      85.66
3       itrh    99      83      93      91.66

  • 正则表达式

  • 如果要想让 awk 识别字符串,必须使用//包含,例如

  • 提取出含有r的行,而且行必须从第2行到第4行查找

[dayuanshuai@idys1 cut_dir] awk '/r/ {if(NR>1 && NR<=4) print}' student_me.txt  
3       itrh    99      83      93      91.66
  • awk判断IP是否合法
# 查看文件内容
[dayuanshuai@idys1 day5] tail -11 num_task_file.txt  
123.45.12.123wq
q123.12.1.1c
1233.1234.1.12c
12.12.123.12
  1.1.2.3 
12.1.212.1.5
1.0.0.0
0.0.0.0
127.12.0.0
12.12.124.123.231.123
192.168.1.0

# 使用 -W re-interval 形式可以支持 {m,n}
# / / 内可以使用正则表达式
# if嵌套的形式为 if(判断式){if (判断式){执行动作}}
[dayuanshuai@idys1 day5] awk -W re-interval -F'.' '/^[[:digit:]]{1,3}.[[:digit:]]{1,3}.[[:digit:]]{1,3}.[[:digit:]]{1,3}$/ {if($1>0 && $1<255 && $2>=0 && $2<255 && $3>=0 && $3<255 && $4>=0 && $4<255) {if(!($2 == 0 && $3 == 0 && $4 == 0)) print $0}}' num_task_file.txt  
12.12.123.12
127.12.0.0
192.168.1.0

# 另外一种形式
[dayuanshuai@idys1 day5] awk -W re-interval -F'.' '/^[[:digit:]].*[[:digit:]]$/ {if(NF == 4 && $1>0 && $1<255 && $2>=0 && $2<255 && $3>=0 && $3<255 && $4>=0 && $4<255) {if(!($2 == 0 && $3 == 0 && $4 == 0)) print $0}}' num_task_file.txt 
12.12.123.12
127.12.0.0
192.168.1.0

  • awk内置变量
awk内置变量作用
$0代表目前 awk 所读入的整行数据。我们已知 awk 是一行一行读入数据 的,$0 就代表当前读入行的整行数据。
$n代表目前读入行的第 n 个字段。
NF当前行拥有的字段(列)总数。
NR当前 awk 所处理的行,是总数据的第几行。
FS用户定义分隔符。awk 的默认分隔符是任何空格,如果想要使用其他分隔符(如:),就需要 FS 变量定义。
ARGC命令行参数个数
ARGV命令行参数数组。
FNR当前文件中的当前记录数(对输入文件起始为 1
OFMT数值的输出格式(默认为%.6g
OFS输出字段的分隔符(默认为空格)
ORS输出记录分隔符(默认为换行符)
RS输入记录分隔符(默认为换行符)
  • 使用awk筛选出可以登录用户的用户名,UID和匹配所在的行数
[dayuanshuai@idys1 day5] awk 'BEGIN{FS=":"} /\/bin\/bash/{printf ("%-12s\t%s\t%s\n",$1,$3,NR)}' /etc/passwd
root            0       1
dayuanshuai     500     23
xiao            501     24
hadoop          502     25
  • 查看sshd这个伪用户的信息
[dayuanshuai@idys1 day5] awk 'BEGIN{FS=":"} $1=="sshd" {print $1"\t"$3"\t行号为:"NR"\t字段数:"NF}' /etc/passwd
sshd    74      行号为:20       字段数:7

  • awk流程控制

  • 查看文件内容

[dayuanshuai@idys1 cut_dir] cat student_me.txt 
ID      Name    PHP     Linux   MySQL   Average
1       idys    82      95      86      87.66
2       fool    74      96      87      85.66
3       itrh    99      83      93      91.66
  • 统计PHP科目成绩总分
[dayuanshuai@idys1 cut_dir] awk '{grade+=$3}END{print "php sum grade="grade}' student_me.txt
php sum grade=255
  • 统计PHP科目平均分
# NR 代表行数
[dayuanshuai@idys1 cut_dir] awk '{grade+=$3}END{print "php sum grade="grade/(NR-1)}' student_me.txt   
php sum grade=85

  • awk 编程中,因为命令语句非常长,在输入格式时需要注意以下内容:
  • 多个条件{动作}可以用空格分割,也可以用回车分割。
  • 在一个动作中,如果需要执行多个命令,需要用;分割,或用回车分割。
  • awk 中,变量的赋值与调用都不需要加入$
  • 条件中判断两个值是否相同,请使用==,以便和变量赋值进行区分。
  • 在第2行到第3行,只要成绩大于80分,就输出名字加以修饰
[dayuanshuai@idys1 cut_dir] awk 'NR>=2 && NR<4 && $3>80{print $2"\tis a good man"}' student_me.txt 
idys    is a good man

  • awk 函数
  • awk 编程也允许在编程时使用函数,形式如下
function 函数名(参数列表){
函数体
}
  • 编写一个函数实现程序判断输出功能
# grade 为传入的参数,由于用户自己控制function 定义函数,之后调用函数
[dayuanshuai@idys1 cut_dir] awk 'function print_grade(grade){ if(NR>1 && $3>grade){print $2"  is a good man"} }{ print_grade(80)}' student_me.txt   
idys  is a good man
itrh  is a good man

  • awk调用脚本

  • awk -f 脚本名即可导入脚本名

  • 通过导入脚本名的方式,实现上述操作

[dayuanshuai@idys1 cut_dir] echo 'function print_grade(grade){ if(NR>1 && $3>grade){print $2"  is a good man"} }{ print_grade(80)}' >input.awk; awk -f input.awk student_me.txt 
idys  is a good man
itrh  is a good man

1.3 sed 命令

  • sed 主要是用来将数据进行选取、替换、删除、新增的命令,我们看看命令的语
  • sed用法格式
    • sed [选项] [动作] 文件名
  • sed选项
选项含义
-n一般 sed 命令会把所有数据都输出到屏幕,如果加入此选择,则只会把经过 sed 命令处理的行输出到屏幕。
-e允许对输入数据应用多条 sed 命令编辑。
-f 脚本文件名sed 脚本中读入 sed 操作。和 awk 命令的-f 非常类似
-rsed 中支持扩展正则表达式。
-ised 的修改结果直接修改读取数据的文件,而不是由屏幕输出

  • sed动作
动作含义
动作: a \追加,在当前行后添加一行或多行。添加多行时,除最后一行外, 每行末尾需要用\代表数据未完结
c \行替换,用 c 后面的字符串替换原数据行,替换多行时,除最后一行外,每行末尾需用\代表数据未完结。
i \插入,在当期行前插入一行或多行。插入多行时,除最后 一行外, 每行末尾需要用\代表数据未完结
d删除,删除指定的行
p打印,输出指定的行
s字串替换,用一个字符串替换另外一个字符串。格式为行范围 s/ 旧字串/新字串/g(和 vim 中的替换格式类似)
g对数据中所有匹配到的内容进行替换,如果没有 g,则只会在第一次匹配成功时做替换操作。例如,一行数据中有 3 个 A,则只会替换第一个 A
w file将缓冲区中的内容写到指定的 file 文件中
&用正则表达式匹配的内容进行替换
\n匹配第 n 个子串,该子串之前在 pattern 中用 \(\) 指定

sed 命令大家要注意,sed 所做的修改并不会直接改变文件的内容(如果是用管道符接收的命令的输出,这种情况连文件都没有),而是把修改结果只显示到屏幕上,除非使用“-i”选项才会直接修改文件

  • 行数据操作
# 查看文件内容
[dayuanshuai@idys1 cut_dir] cat student_me.txt 
ID      Name    PHP     Linux   MySQL   Average
1       idys    82      95      86      87.66
2       fool    74      96      87      85.66
3       itrh    99      83      93      91.66

# 不加-n的话会将所有数据输出至屏幕
[dayuanshuai@idys1 cut_dir] sed '2p' student_me.txt 
ID      Name    PHP     Linux   MySQL   Average
1       idys    82      95      86      87.66
1       idys    82      95      86      87.66
2       fool    74      96      87      85.66
3       itrh    99      83      93      91.66

# 只显示第二行
[dayuanshuai@idys1 cut_dir] sed -n '2p' student_me.txt 
1       idys    82      95      86      87.66
  • 添加多行内容
# 从第二行添加内容
[dayuanshuai@idys1 cut_dir] sed '2a whoami\
> how are you\
> and me?' student_me.txt
ID      Name    PHP     Linux   MySQL   Average
1       idys    82      95      86      87.66
whoami
how are you
and me?
2       fool    74      96      87      85.66
3       itrh    99      83      93      91.66
  • 删除数据
# 删除第二行
[dayuanshuai@idys1 cut_dir] sed '2d' student_me.txt 
ID      Name    PHP     Linux   MySQL   Average
2       fool    74      96      87      85.66
3       itrh    99      83      93      91.66
  • 在第四行前面添加多行
[dayuanshuai@idys1 cut_dir] sed '4i whoami\
> how \
> are \
> you\
> ' student_me.txt
ID      Name    PHP     Linux   MySQL   Average
1       idys    82      95      86      87.66
2       fool    74      96      87      85.66
whoami
how 
are 
you

3       itrh    99      83      93      91.66
  • 只显示添加的行
[dayuanshuai@idys1 cut_dir] sed -n '2i man\
> hello\
> ' student_me.txt
man
hello
  • 将第二行的82替换为12
[dayuanshuai@idys1 cut_dir] cat student_me.txt 
ID      Name    PHP     Linux   MySQL   Average
1       idys    82      95      86      87.66
2       fool    74      96      87      85.66
3       itrh    99      83      93      91.66

[dayuanshuai@idys1 cut_dir] sed '2s/82/12/' student_me.txt  
ID      Name    PHP     Linux   MySQL   Average
1       idys    12      95      86      87.66
2       fool    74      96      87      85.66
3       itrh    99      83      93      91.66
  • 将每一行出现的第一个h替换为,|@|
# 查看文件内容
[dayuanshuai@idys1 cut_dir] cat service_test.txt 
how how are are you
you are me are me how how are me 
me is idiot idiot how are how 
all work, no play, make jack fool
  • 查看目标文件夹里面内容是否含有fstab的文件
  • grep的参数说明
    • -R 在目录下递归查找
    • -l:只显示文件名,如果不使用-l参数的话,那么就会既显示文件名,又显示文件名中对应匹配该字符串的行
# 查找 /etc/ 目录下所有内容能与正则表达式匹配的文件,并且显示出该文件的文件名,及其与正则表达式匹配的行
[root@idys1 ~] grep -E '^root.*[[:digit:]]+.*[^:]$' -R /etc/
/etc/selinux/targeted/seusers:root:unconfined_u:s0-s0:c0.c1023
/etc/selinux/targeted/modules/active/seusers.final:root:unconfined_u:s0-s0:c0.c1023
/etc/passwd:root:x:0:0:root:/root:/bin/bash
/etc/services:rootd           1094/tcp                # ROOTD
/etc/services:rootd           1094/udp                # ROOTD
/etc/passwd-:root:x:0:0:root:/root:/bin/bash

# 加了 -l 参数后,只显示文件名
[root@idys1 ~] grep -E '^root.*[[:digit:]]+.*[^:]$' -Rl /etc/
/etc/selinux/targeted/seusers
/etc/selinux/targeted/modules/active/seusers.final
/etc/passwd
/etc/services
/etc/passwd-
  • /home目录下,查找后缀名为.txt的文件里面内容中与正则表达式匹配的文件。找出来之后显示文件名。行号。及其匹配的行.
# grep -n 显示行号 -E 支持扩展正则 -R 文件夹下递归查找
[root@idys1 ~] grep -RnE --include="*.txt" '^[[:digit:]]+[[:space:]]+idys' /home 
/home/dayuanshuai/day5/cut_dir/student_me.txt:2:1       idys    82      95      86      87.66
  • sed对文件进行修改,同时为该文件做一个备份
# 首先 查看文件内容
[dayuanshuai@idys1 cut_dir] cat student_me.txt 
ID      Name    PHP     Linux   MySQL   Average
1       idys    82      95      86      87.66
2       fool    74      96      87      85.66
3       itrh    99      83      93      91.66

# 查看该目录下有哪些文件
[dayuanshuai@idys1 cut_dir] ls
input.awk  service_test.txt  student_me.txt  student_me.txt.bak  student.txt

# 修改student_me.txt文件,在文件第二行 添加 whoami 
[dayuanshuai@idys1 cut_dir] sed -i.bak '2a whoami' student_me.txt  

# 查看目录下的文件,发现多出一个 student_me.txt.bak 文件
[dayuanshuai@idys1 cut_dir] ls
87  input.awk  service_test.txt  student_me.txt  student_me.txt.bak  student.txt

# 查看student_me.txt.bak和student_me.txt文件
[dayuanshuai@idys1 cut_dir] cat student_me.txt
ID      Name    PHP     Linux   MySQL   Average
1       idys    82      95      86      87.66
whoami
2       fool    74      96      87      85.66
3       itrh    99      83      93      91.66
[dayuanshuai@idys1 cut_dir] cat student_me.txt.bak
ID      Name    PHP     Linux   MySQL   Average
1       idys    82      95      86      87.66
2       fool    74      96      87      85.66
3       itrh    99      83      93      91.66
  • 使用sed,查找idys,在其后面添加换行符
[dayuanshuai@idys1 cut_dir] sed  's/idys/&\n/g' student_me.txt 
ID      Name    PHP     Linux   MySQL   Average
1       idys
        82      95      86      87.66
2       fool    74      96      87      85.66
3       itrh    99      83      93      91.66
  • 查找idys字符串,在其前面添加换行
[dayuanshuai@idys1 cut_dir] sed  's/idys/\n&/g' student_me.txt  
ID      Name    PHP     Linux   MySQL   Average
1
idys    82      95      86      87.66
2       fool    74      96      87      85.66
3       itrh    99      83      93      91.66
  • 匹配idys这一行,然后将idys这一行的内容写入到新文件当中
# 匹配含有idys字符串的哪一行,然后将其写入到 A.txt 文件中
# w 后接文件名 表示将匹配到的内容 写入到新文件中
[dayuanshuai@idys1 cut_dir] sed -n '/idys/w A.txt' student_me.txt
[dayuanshuai@idys1 cut_dir] cat A.txt 
1       idys    82      95      86      87.66
  • 将第二行到第三行内容复制到其后面一行
# & 代表前面匹配到的内容
[dayuanshuai@idys1 cut_dir] sed '2,3s/.*/&\n&/g' student_me.txt
ID      Name    PHP     Linux   MySQL   Average
1       idys    82      95      86      87.66
1       idys    82      95      86      87.66
2       fool    74      96      87      85.66
2       fool    74      96      87      85.66
3       itrh    99      83      93      91.66
  • 只显示id和姓名
[dayuanshuai@idys1 cut_dir] cat student_me.txt
ID      Name    PHP     Linux   MySQL   Average
1       idys    82      95      86      87.66
2       fool    74      96      87      85.66
3       itrh    99      83      93      91.66

# 使用 -e 可以使用多条命令匹配, \(\)用于匹配整个\(\)里面的内容,\1引用前面\(\)里面的内容
[dayuanshuai@idys1 cut_dir] sed  -e 's/\([[:digit:]]\)[[:space:]]\+\([[:alpha:]]\+\).*/\1\t\2/g' -e '1d' student_me.txt
1       idys
2       fool
3       itrh

# 开启扩展正则表达式
[dayuanshuai@idys1 cut_dir] sed -r -e 's/([[:digit:]])[[:space:]]+([[:alpha:]]+).*/\1\t\2/g' -e '1d' student_me.txt       
1       idys
2       fool
3       itrh
  • sed把某个单词替换为另外一个字符串
# 查看文件内容
[dayuanshuai@idys1 cut_dir] cat sed_test.txt 
my A A a ha hahaha who who
w who who w who my
my m m f for for in i in

# 想将 单独的 a 替换为 lol, 如果使用以下命令, 则会将所有的a替换为lol
[dayuanshuai@idys1 cut_dir] sed 's/a/lol/g' sed_test.txt 
my A A lol hlol hlolhlolhlol who who
w who who w who my
my m m f for for in i in

# 以下才是正确的将 单独的A单词替换为 lol
[dayuanshuai@idys1 cut_dir] sed 's/\<a\>/lol/g' sed_test.txt 
my A A lol ha hahaha who who
w who who w who my
my m m f for for in i in

# 把单独的a单词替换为lol,同时不区分大小写
[dayuanshuai@idys1 cut_dir] sed 's/\<a\>/lol/ig' sed_test.txt  # 这种形式 's///i'即使不区分大小写,替换
my lol lol lol ha hahaha who who
w who who w who my
my m m f for for in i in

# 不区分who的大小写,将其全局替换为 Love
[dayuanshuai@idys1 cut_dir] sed 's/who/Love/ig' sed_test.txt 
my A A a ha hahaha Love Love
w Love Love w Love my
my m m f fOr For FOR in i in

  • 将每行中的第二个w替换为me
# 查看文件内容
[dayuanshuai@idys1 cut_dir] cat sed_test.txt 
my A A a ha hahaha who who
w who Who w wHo my
my m m f fOr For FOR in i in

# 将每行中的第2个w替换为 me
[dayuanshuai@idys1 cut_dir] sed 's/w/me/i2' sed_test.txt  
my A A a ha hahaha who meho
w meho Who w wHo my
my m m f fOr For FOR in i in
  • 将每行中,从第2w开始替换为L
# 's///2g'代表从第2个开始进行替换
[dayuanshuai@idys1 cut_dir] sed 's/w/L/i2g' sed_test.txt      
my A A a ha hahaha who Lho
w Lho Lho L LHo my
my m m f fOr For FOR in i in
  • 将第一行的第一个a替换为Q
# 0,/要替换的内容/s/要替换的内容/替换后的内容/
# 替换第一行第一个a
[dayuanshuai@idys1 cut_dir] sed '0,/a/s/a/Q/i' sed_test.txt  
my Q A a ha hahaha who who
w who Who w wHo my
my m m f fOr For FOR in i in
  • 替换一个行的所有a
[dayuanshuai@idys1 cut_dir] sed '0,/a/s/a/Q/ig' sed_test.txt  
my Q Q Q hQ hQhQhQ who who
w who Who w wHo my
my m m f fOr For FOR in i in

# 替换第一行的所有a
[dayuanshuai@idys1 cut_dir] sed '1s/a/Q/g' sed_test.txt 
my A A Q hQ hQhQhQ who who
w who Who w wHo my
my m m f fOr For FOR in i in
  • 将前两行的o替换为Q
# 1, 代表前两行
[dayuanshuai@idys1 cut_dir] sed '1,/o/s/o/Q/g' sed_test.txt  
my A A a ha hahaha whQ whQ
w whQ WhQ w wHQ my
my m m f fOr For FOR in i in
  • 将前两行的每一行的第一个o替换为Q
[dayuanshuai@idys1 cut_dir] sed '1,/o/s/o/Q/' sed_test.txt  
my A A a ha hahaha whQ who
w whQ Who w wHo my
my m m f fOr For FOR in i in
  • 字符/sed命令中作为定界符使用,其实任意字符都可以当作定界符
# 第二行第二个 w 替换为 kk
[dayuanshuai@idys1 cut_dir] sed '2s|w|kk|2' sed_test.txt  
my A A a ha hahaha who who
w kkho Who w wHo my
my m m f fOr For FOR in i in
  • 将含有单词who的行删除
[dayuanshuai@idys1 cut_dir] sed '/\<who\>/d' sed_test.txt  
my m m f fOr For FOR in i in
  • 为第一行的所有单词,套上[]
[dayuanshuai@idys1 cut_dir] sed -r '1s/\w+/[&]/g' sed_test.txt 
[my] [A] [A] [a] [ha] [hahaha] [who] [who]
w who Who w wHo my
my m m f fOr For FOR in i in
  • Sed命令还可以组合多个表达式
# 首先全局替换然后,删除,最后插入
[dayuanshuai@idys1 cut_dir] sed -r 's/who/idys/g;2d; 1a sdasdsadasd' sed_test.txt  
my A A a ha hahaha idys idys
sdasdsadasd
my m m f fOr For FOR in i in

# 这个似乎没有起作用
[dayuanshuai@idys1 cut_dir] sed -r 's/who/idys/g;2d; 2a sdasdsadasd' sed_test.txt 
my A A a ha hahaha idys idys
my m m f fOr For FOR in i in

# 写在第3行后面添加就有效了
[dayuanshuai@idys1 cut_dir] sed -r 's/who/idys/g;2d; 3a sdasdsadasd\n' sed_test.txt  
my A A a ha hahaha idys idys
my m m f fOr For FOR in i in
sdasdsadasd

# 最后一行,后面添加 sdasdsadasd
[dayuanshuai@idys1 cut_dir] sed -r 's/who/idys/g;2d; $a sdasdsadasd\n' sed_test.txt  
my A A a ha hahaha idys idys
my m m f fOr For FOR in i in
sdasdsadasd


  • sed实现值得提取
# 文本内容如下。现在我们要将 所有的 value 提取出来
[dayuanshuai@idys1 cut_dir] cat my_task1.txt 
type1=value1   type2=value2   type3=value3
type1=value1   type2=value2   type3=value3

# 这样即可
[dayuanshuai@idys1 cut_dir] sed -r 's/[^[:space:]]+=//g' my_task1.txt 
value1   value2   value3
value1   value2   value3

  • /bin/bash修改为/bin/sh,同时打印输出,修改的行
[dayuanshuai@idys1 cut_dir] sed -n 's|/bin/bash|/bin/sh|gp' /etc/passwd
root:x:0:0:root:/root:/bin/sh
dayuanshuai:x:500:500::/home/dayuanshuai:/bin/sh
xiao:x:501:501::/home/xiao:/bin/sh
hadoop:x:502:502::/home/hadoop:/bin/sh
  • 从第二行开始删除所有的name
[dayuanshuai@idys1 cut_dir] sed -r '2,4s/[[:alpha:]]+//g' student_me.txt 
ID      Name    PHP     Linux   MySQL   Average
1               82      95      86      87.66
2               74      96      87      85.66
3               99      83      93      91.66
  • 删除idys前后各一行,中的人名
[dayuanshuai@idys1 cut_dir] sed -re '2s/[[:alpha:]]+//g;4s/[[:alpha:]]+//g' student_me.txt
ID      Name    PHP     Linux   MySQL   Average
1               82      95      86      87.66
2       fool    74      96      87      85.66
3               99      83      93      91.66
  • 从第二行开始到最后一行,每行往下复制一行
# $ 代表最后一行, & 指代前面匹配的内容
[dayuanshuai@idys1 cut_dir] sed -r "2,\$s/.*/&\n&/g" student_me.txt 
ID      Name    PHP     Linux   MySQL   Average
1       idys    82      95      86      87.66
1       idys    82      95      86      87.66
2       fool    74      96      87      85.66
2       fool    74      96      87      85.66
3       itrh    99      83      93      91.66
3       itrh    99      83      93      91.66
  • 在固定的内容或者行后面添加新行
# 在 echo "2" 后面添加 echo "3"
[dayuanshuai@idys1 cut_dir] sed '/echo "2"/a  \echo "3";' echo_test_txt 
echo "1";
echo "2";
echo "3";
echo "4";
echo "5";

# 在第二行后面添加 echo "3"
[dayuanshuai@idys1 cut_dir] sed '2a echo "3";' echo_test_txt 
echo "1";
echo "2";
echo "3";
echo "4";
echo "5";
  • 每行后面追加空行
[dayuanshuai@idys1 cut_dir] sed '/[^[:space:]]/a \ ' echo_test_txt    
echo "1";
 
echo "2";
 
echo "4";
 
echo "5";

# G 代表将 将hold space中的内容拷贝到pattern space中
[dayuanshuai@idys1 cut_dir] sed 'G' echo_test_txt                    
echo "1";

echo "2";

echo "4";

echo "5";

  • 关于sed保留空间与模式空间的操作命令
命令含义
g:[address[,address]]ghold space中的内容拷贝到pattern space中,原来pattern space里的内容清除
G:[address[,address]]Ghold space中的内容appendpattern space\n后。
h:[address[,address]]hpattern space中的内容拷贝到hold space中,原来的hold space里的内容被清除。
H[address[,address]]Hpattern space中的内容appendhold space\n后。
d[address[,address]]d删除pattern中的所有行,并读入下一新行到pattern中。
D[address[,address]]D删除multiline pattern中的第一行,不读入下一行。
x交换保持空间和模式空间的内容。
p打印当前模式空间内容,追加到默认输出之后
P打印当前模式空间开端至\n的内容,并追加到默认输出之前
n命令简单来说就是提前读取下一行,覆盖模型空间前一行(并没有删除,因此依然打印至标准输出),如果命令未执行成功(并非跳过:前面条件不匹配),则放弃执行之后的任何命令,并对新读取的内容,重头执行sed
N命令简单来说就是追加下一行到模式空间,同时将两行看做一行,但是两行之间依然含有\n换行符,如果命令未执行成功(并非跳过:前面条件不匹配),则放弃之后任何命令,并对新读取的内容,重头执行sed
1!G第一行不执行G命令,从第二行开始执行
$!d最后一行不删除
  • 打印输出文件的奇数行
# 查看文件内容
[dayuanshuai@idys1 cut_dir] cat echo_test_txt 
echo "1";
echo "2";
echo "3";
echo "4";
echo "5";

# 打印输出奇数数行
[dayuanshuai@idys1 cut_dir] sed -n '$!N;P' echo_test_txt  
echo "1";
echo "3";
echo "5";

# 查看文件内容
[dayuanshuai@idys1 cut_dir] cat echo_T2.txt 
echo "1";
echo "2";
echo "3";
echo "4";

# 打印输出奇数行
[dayuanshuai@idys1 cut_dir] sed -n '$!N;P' echo_T2.txt   
echo "1";
echo "3";
  • 打印输出偶数行
# 查看文件内容
[dayuanshuai@idys1 cut_dir] cat echo_test_txt 
echo "1";
echo "2";
echo "3";
echo "4";
echo "5";

# 打印输出偶数行
[dayuanshuai@idys1 cut_dir] sed -n 'n;p' echo_test_txt 
echo "2";
echo "4";

# 查看文件内容
[dayuanshuai@idys1 cut_dir] cat echo_T2.txt 
echo "1";
echo "2";
echo "3";
echo "4";

# 打印输出所有的偶数行
[dayuanshuai@idys1 cut_dir] sed -n 'n;p' echo_T2.txt 
echo "2";
echo "4";
  • 倒序输出所有的奇数行
# 查看文件内容
[dayuanshuai@idys1 cut_dir] cat echo_test_txt 
echo "1";
echo "2";
echo "3";
echo "4";
echo "5";

# 倒序输出所有奇数行, 1!G 第一行不执行 G, 
# G 将 hold space 里面的内容复制追加到 pattern space 里面
# N 直接读取两行,行中用\n 隔开,
# s/// 替换
# h 将 patter space 里面的内容 复制覆盖到 hold space里面
# !$d 最后一行不执行 删除
[dayuanshuai@idys1 cut_dir] sed -r '1!G;N;s/(.*)\n(.*)/\1/;h;$!d' echo_test_txt              
echo "5";
echo "3";
echo "1";

[dayuanshuai@idys1 cut_dir] cat echo_T2.txt 
echo "1";
echo "2";
echo "3";
echo "4";

# 倒序输出所有的奇数行
[dayuanshuai@idys1 cut_dir] sed -r '1!G;N;s/(.*)\n(.*)/\1/g;h;$!d' echo_T2.txt 
echo "3";
echo "1";
  • 倒序输出所有偶数行
# 先输出所有偶数行,然后倒序
[dayuanshuai@idys1 cut_dir] sed -n 'n;p' echo_T2.txt | sed '1!G;h;$!d'
echo "4";
echo "2";
  • 将所有奇数行倒序输出,且逆序输出所有字符串
# 原字符串内容
[dayuanshuai@idys1 cut_dir] cat echo_test_txt 
echo "1";
echo "2";
echo "3";
echo "4";
echo "5";

# rev 代表逆序输出字符串
[dayuanshuai@idys1 cut_dir] sed -r '1!G;N;s/(.*)\n(.*)/\1/g;h;$!d' echo_test_txt | rev
;"5" ohce
;"3" ohce
;"1" ohce

# 倒序输出字符串
[dayuanshuai@idys1 ~] str=hello;len=${#str};for((i=$len-1;i>=0;i--));do echo -e "${str:$i:1}\c";done;echo -e "\n"
olleh

# 数组的形式倒序输出
[dayuanshuai@idys1 cut_dir] str=`echo "hello" | sed 's/./& /g'`;array=($str);len=${#array[@]};for((i=$len-1;i>=0;i--));do echo -e "${array[$i]}\c";done;echo -e "\n"        
olleh

# 发现倒序输出对有空格的无效,倒序后没有打印空格
[dayuanshuai@idys1 cut_dir] str=`echo "hello world" | sed 's/./& /g'`;array=($str);len=${#array[@]};for((i=$len-1;i>=0;i--));do echo -e "${array[$i]}\c";done;echo -e "\n"  
dlrowolleh
  • sed流程控制

    • b:无条件跳转
    • tT:有条件跳转
  • 如果一行中,含有AA,那么就在AA后面末尾添加,YES,反之添加NO

# 咦,我们发现 匹配到AA 的行,会在价位加 YES,没错。但是没有匹配到 AA的行却在结尾加上了
# NO 和 YES,这是为什么呢。这是因为,如果匹配到了AA那么直接跳转到 LABEL,如果没有匹配到AA的话,则会先执行 s/$/ NO/g 语句,然后 执行 s/$/ YES/g。这就是 NO和 YES都出现的原因
[dayuanshuai@idys1 sed_test] sed '/AA/b LABEL; s/$/ NO/g;:LABEL;s/$/ YES/g' sed_b.txt   
AA YES
BC NO YES
AA YES
CB NO YES
CC NO YES
AA YES

# 解决办法,在NO后面的语句里面,再加上一个 b 语句,则不会继续执行LABEL 后面的语句
[dayuanshuai@idys1 sed_test] sed '/AA/b LABEL; s/$/ NO/g;b;:LABEL;s/$/ YES/g' sed_b.txt 
AA YES
BC NO
AA YES
CB NO
CC NO
AA YES
  • sed命令的b语句详解
# 如果匹配到了 /AA/ 那么跳转到 top 执行 s/$/who/g,如果没有匹配到 /AA/ 那么先执行s/$/NO/g 
# 再执行s/$/am/g 最后执行 s/$/who/g
[dayuanshuai@idys1 sed_test] sed '/AA/b top;s/$/NO/g;s/$/am/g;:top;s/$/who/g' sed_b.txt      
AAwho
BCNOamwho
AAwho
CBNOamwho
CCNOamwho
AAwho

# 因为 b 后面没有写 跳转标签。 那么当匹配到 /AA/ 时,直接跳转到行尾,什么也不执行。如果没有匹配到AA,那么则 一直往后执行语句  ( 先执行 s/$/NO/g  然后执行 s/$/am/g  最后执行 s/$/who/g )
[dayuanshuai@idys1 sed_test] sed '/AA/b;s/$/NO/g;:top;s/$/am/g;s/$/who/g' sed_b.txt    
AA
BCNOamwho
AA
CBNOamwho
CCNOamwho
AA
  • 我们再来看看t命令
# 倘若 前面 命令正确执行,那么t 直接跳转到行尾。什么都不执行。
# 倘若 前面的 命令没有执行成功。那么则 往下执行 s/$/ NO/g
[dayuanshuai@idys1 sed_test] sed  '/^AA/s/$/ YES/g; t; s/$/ NO/g' sed_b.txt 
AA YES
BC NO
AA YES
CB NO
CC NO
AA YES

# 查看命令的执行情况
[dayuanshuai@idys1 sed_test] sed '$a ww' sed_b.txt 
AA
BC
AA
CB
CC
AA
ww

# 在 sed 命令后面添加 新的一行。 为 ww
[dayuanshuai@idys1 sed_test] sed -i '$a ww' sed_b.txt 

# 一次读取 两行, 然后打印第一行。 t 用于判断。 前面是否正确执行。 执行成功 跳转到 LABEL, 不成功则往后执行
[dayuanshuai@idys1 sed_test] sed -n ':LABEL; $!N;P;t LABEL' sed_b.txt 
AA
AA
CC
ww


  • 关于sed命令的y
    • s替换的是整体,y替换的是每一字母对应的单个字母
  • 关于ys的区别演示
# 首先查看文件内容
[dayuanshuai@idys1 sed_test] cat sed_y_s_test.txt 
ABC AB A C 
ABCDE ABC A BC 
CBA BA CA

# 将单个字母A替换为w 将单个字母B替换为h 将单个字母C替换为o
[dayuanshuai@idys1 sed_test] sed 'y/ABC/who/' sed_y_s_test.txt  
who wh w o 
whoDE who w ho 
ohw hw ow

# 将ABC作为一个整体替换为 who
[dayuanshuai@idys1 sed_test] sed 's/ABC/who/g' sed_y_s_test.txt  
who AB A C 
whoDE who A BC 
CBA BA CA


02. 字符处理命令

2.1 排序命令sort

  • 使用格式

    • sort [选项] 文件名
  • 选项及其含义

选项含义
-f忽略大小写
-b忽略每行前面的空白部分
-n以数值型进行排序,默认使用字符串型排序
-r反向排序
-u删除重复行。就是 uniq 命令
-t指定分隔符,默认是分隔符是制表符
-kn[,m]按照指定的字段范围排序。从第 n 字段开始,m 字段结束(默认到行尾)
  • sort 命令默认是用每行开头第一个字符来进行排序的

  • /etc/passwd文件里面按照UID来排序,排出来的结果只显示nameUID

# 首先查看文件内容
[dayuanshuai@idys1 sed_test] cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin
operator:x:11:0:operator:/root:/sbin/nologin
games:x:12:100:games:/usr/games:/sbin/nologin
gopher:x:13:30:gopher:/var/gopher:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
nobody:x:99:99:Nobody:/:/sbin/nologin
***************************************
**********************

# 用 sort 排序。然后用 awk输出

[dayuanshuai@idys1 sed_test] sort -t":" -k 3 -n /etc/passwd | awk -F":" '{printf ("%-15s%-5i\n",$1,$3)}'
root           0    
bin            1    
daemon         2    
adm            3    
lp             4    
sync           5    
shutdown       6    
halt           7    
mail           8    
uucp           10   
operator       11   
games          12   
gopher         13   
ftp            14   
ntp            38   
vcsa           69   
sshd           74   
dbus           81   
postfix        89   
nobody         99   
dhcpd          177  
saslauth       499  
dayuanshuai    500  
xiao           501  
hadoop         502  
test2          503  
peiqi          504  


# 利用 cat 提取出 内容
[dayuanshuai@idys1 sed_test] sort -t":" -k 3 -n /etc/passwd | cut -d":" -f1,3
root:0
bin:1
daemon:2
adm:3
lp:4
sync:5
shutdown:6
halt:7
mail:8
uucp:10
operator:11
games:12
gopher:13
ftp:14
ntp:38
vcsa:69
sshd:74
dbus:81
postfix:89
nobody:99
dhcpd:177
saslauth:499
dayuanshuai:500
xiao:501
hadoop:502
test2:503
peiqi:504
  • /etc/passwd按照UID数字大小排序,排序后显示用户名和UID,然后显示最后10行和前9
[dayuanshuai@idys1 sed_test] sort -t":" -k 3 -rn /etc/passwd | cut -d":" -f1,3 | awk '{line[NR]=$0} END{for(i=1;i<=NR;i++){if(i==10){i=NR-9}print line[i]} }'
peiqi:504
test2:503
hadoop:502
xiao:501
dayuanshuai:500
saslauth:499
dhcpd:177
nobody:99
postfix:89
uucp:10
mail:8
halt:7
shutdown:6
sync:5
lp:4
adm:3
daemon:2
bin:1
root:0

2.2 uniq

  • uniq 命令是用来取消重复行的命令,其实和sort -u选项是一样的。命令格式如下
  • 命令格式
    • uniq [选项] 文件名
    • uniq -i 忽略大小写
    • uniq -c:显示重复的次数
    • uniq -d:只显示重复的行
    • uniq -u:只显示出现一次的行
    • -f n--skip-fields=n 忽略前N个字段。字段由空白字符(空格符、Tab)分隔
    • -s<字符位置>或--skip-chars=<字符位置> 忽略比较指定的字符。-s n:忽略前n个字符,从n+1个字符开始比较
    • -w<字符位置>或--check-chars=<字符位置> 指定要比较的字符。-w n:只比较前n个字符,对每行第n个字符以后的内容不作对照
[dayuanshuai@idys1 sed_test] seq 10 | sed -r 's/.*/&\n&/g' | sed -r '10,$s/.*/&\n&wqe/g'
1
1
2
2
3
3
4
4
5
5
5wqe
6
6wqe
6
6wqe
7
7wqe
7
7wqe
8
8wqe
8
8wqe
9
9wqe
9
9wqe
10
10wqe
10
10wqe
# 上面的内容有很多重复的,而且有些重复得内容不是连续的。现在我们想要将 重复不连续的行也删除
# 将这些内容先排序,后删除重复。就可以解决重复不连续的问题
[dayuanshuai@idys1 sed_test] seq 10 | sed -r 's/.*/&\n&/g' | sed -r '10,$s/.*/&\n&wqe/g' | sort -n | uniq 
1
2
3
4
5
5wqe
6
6wqe
7
7wqe
8
8wqe
9
9wqe
10
10wqe

[dayuanshuai@idys1 sed_test] cat uniq_d.txt 
AA
AA
AA
BB

# -d 只显示重复的行
[dayuanshuai@idys1 sed_test] uniq -dc uniq_d.txt 
      3 AA

# 只显示重复一次的行
[dayuanshuai@idys1 sed_test] uniq -uc uniq_d.txt  
      1 BB

2.3 统计命令 wc

  • 命令格式
    • wc [选项] 文件名
  • 选项:
选项含义
-l只统计行数
-w只统计单词数
-m只统计字符数
  • 首先生成一个含有重复行,而且重复行不连续。大小写不一致的文本
# sed -ri 's/.*/&\n&/g' sed_y_s_test.txt 将每一行重复一遍
# num=`wc -l sed_y_s_test.txt | cut -d" " -f1` 得出总行数
# sed -i '5,'"$(($num-1))"'y/B/b/' sed_y_s_test.txt  将变量num引入sed 中,从第五行到最后一行的前一行都把大写字母 B 变为小写字母b
# 这样下来该文本含有重复的行,而且含有重复不连续的行,而且也含有字母大小不一致,但是内容相等的行
[dayuanshuai@idys1 sed_test] sed -ri 's/.*/&\n&/g' sed_y_s_test.txt;num=`wc -l sed_y_s_test.txt | cut -d" " -f1`;sed -i '5,'"$(($num-1))"'y/B/b/' sed_y_s_test.txt
[dayuanshuai@idys1 sed_test] cat sed_y_s_test.txt 
ABC AB A C 
ABC AB A C 
ABCDE ABC A BC 
ABCDE ABC A BC 
CbA bA CA
CbA bA CA
CbA bA CA
CbA bA CA
AbCDE AbC A bC 
AbCDE AbC A bC 
CbA bA CA
CbA bA CA
AbCDE AbC A bC 
AbCDE AbC A bC 
CbA bA CA
CBA BA CA

# 统计重复的行,而且显示重复的次数,忽略大小写
[dayuanshuai@idys1 sed_test] sort -f sed_y_s_test.txt | uniq -ic
      2 ABC AB A C 
      6 AbCDE AbC A bC 
      8 CbA bA CA

03. 条件判断

3.1按照文件类型进行判断

测试选项作用
-b 文件判断该文件是否存在,并且是否为块设备文件(是块设备文件为真)
-c 文件判断该文件是否存在,并且是否为字符设备文件(是字符设备文件为真)
-d 文件判断该文件是否存在,并且是否为目录文件(是目录为真)
-e 文件判断该文件是否存在(存在为真)
-f 文件判断该文件是否存在,并且是否为普通文件(是普通文件为真)
-L 文件判断该文件是否存在,并且是否为符号链接文件(是符号链接文件为真)
-p 文件判断该文件是否存在,并且是否为管道文件(是管道文件为真)
-s 文件判断该文件是否存在,并且是否为非空(非空为真)
-S 文件判断该文件是否存在,并且是否为套接字文件(是套接字文件为真)
  • 多行if,elif,else语句写为一行
# 判断 /root/fstab 文件是否存在,然后判断 /etc/fatab 文件是否存在
[dayuanshuai@idys1 sed_test] if [ -e /root/fastab ]; then echo "/root/fatab yes";elif [ -e /etc/fstab ];then echo "/etc/fstab yes";else echo "NO"; fi; 
/etc/fstab yes
  • 当然也可以用test命令测试,以下测试目录
# 测试目录是否存在
[dayuanshuai@idys1 sed_test] test -d /root;echo $?
0
  • 没有if的分支语句
[dayuanshuai@idys1 sed_test] [ -e /etc/fatab ] && echo "yes" || echo "NO"
NO

3.2 按照文件权限进行判断

测试选项作用
-r 文件判断该文件是否存在,并且是否该文件拥有读权限(有读权限为真)
-w 文件判断该文件是否存在,并且是否该文件拥有写权限(有写权限为真)
-x 文件判断该文件是否存在,并且是否该文件拥有执行权限(有执行权限为真)
-u 文件判断该文件是否存在,并且是否该文件拥有 SUID 权限(有 SUID 权限为真)
-g 文件判断该文件是否存在,并且是否该文件拥有SGID 权限(有 SGID 权限为真)
-k 文件判断该文件是否存在,并且是否该文件拥有 SBit 权限(有 SBit 权限为真)
  • 测试文件权限
[dayuanshuai@idys1 sed_test] ls -l
总用量 12
-rw-rw-r-- 1 dayuanshuai dayuanshuai  21 8月  13 18:04 sed_b.txt
-rw-rw-r-- 1 dayuanshuai dayuanshuai 200 8月  14 00:22 sed_y_s_test.txt
-rw-rw-r-- 1 dayuanshuai dayuanshuai  12 8月  14 00:36 uniq_d.txt
[dayuanshuai@idys1 sed_test] [ -w sed_b.txt ] && echo "yes" || echo "No"
yes

3.3 两个文件之间进行比较

测试选项作用
文件 1 -nt 文件 2判断文件1 的修改时间是否比文件2的新(如果新则为真)
文件 1 -ot 文件 2判断文件1的修改时间是否比文件2的旧(如果旧则为真)
文件 1 -ef 文件 2判断文件1 是否和文件2Inode 号一致,可以理解为两个文件是否为同一个文件。这个判断用于判断硬链接是很好的方法
  • 判断两个文件是否为硬链接
# 首先创建一个文件
[dayuanshuai@idys1 sed_test] ln sed_y_s_test.txt sed_y_s_test.txt.hard_ln 

# 判断是否为硬链接
[dayuanshuai@idys1 sed_test] [ sed_y_s_test.txt -ef sed_y_s_test.txt ] && echo "YES" || echo "NO"
YES

3.4 两个整数之间比较

测试选项作用
整数 1 -eq 整数 2判断整数 1 是否和整数 2 相等(相等为真)
整数 1 -ne 整数 2判断整数 1 是否和整数 2 不相等(不相等位置)
整数 1 -gt 整数 2判断整数 1 是否大于整数 2(大于为真)
整数 1 -lt 整数 2判断整数 1 是否小于整数 2(小于位置)
整数 1 -ge 整数 2判断整数 1 是否大于等于整数 2(大于等于为真)
整数 1 -le 整数 2判断整数 1 是否小于等于整数 2(小于等于为真)
  • 测试条件演示
[dayuanshuai@idys1 sed_test] [ 103 -ge 103 ] && echo "YES" || echo "NO"
YES

3.5 字符串的判断

测试选项作用
-z 字符串判断字符串是否为空(为空返回真)
-n 字符串判断字符串是否为非空(非空返回真)
字串 1 ==字串 2判断字符串 1 是否和字符串 2 相等(相等返回真)
字串 1 != 字串 2判断字符串 1 是否和字符串 2 不相等(不相等返回真)
  • 这里附带说以下数组
# 定义 数组 array[0]为 12 array[1] 为23
[dayuanshuai@idys1 sed_test] array[0]=12
[dayuanshuai@idys1 sed_test] array[1]=23

# 遍历数组
[dayuanshuai@idys1 sed_test] for((i=0;i<=1;i++));do echo ${array[$i]};done
12
23

# 打印数组的所有元素
[dayuanshuai@idys1 sed_test] echo ${array[*]}
12 23

[dayuanshuai@idys1 sed_test] echo ${array[@]}
12 23

# 定义数组
[dayuanshuai@idys1 sed_test] array=(12 34 56 12 15 16 89 97)

# 遍历数组
[dayuanshuai@idys1 sed_test] for i in ${array[@]};do echo $i;done
12
34
56
12
15
16
89
97

# 获得数组长度
[dayuanshuai@idys1 sed_test] len=${#array[@]}
[dayuanshuai@idys1 sed_test] echo $len
8

# 获得数组的某个下标的值
[dayuanshuai@idys1 sed_test] echo ${array[2]}
56

# 定义数组
[dayuanshuai@idys1 sed_test] my_day=([1]=ha [2]=wu [3]=he [4]=id)

# 遍历数组
[dayuanshuai@idys1 sed_test] len=${#my_day[@]};for((i=1;i<$len;i++));do echo ${my_day[$i]};done
ha
wu
he

# 打印数组元素
[dayuanshuai@idys1 sed_test] echo ${my_day[@]}
ha wu he id

# 可以看到以 for in 的方式获得数组元素时, 不加双引号。 * 与 @ 得到的结果一样
# 加了双引号 会把 ${my_day[*]}看作一个整体,直接输出, 而${my_day[@]}仍然遍历数组元素
[dayuanshuai@idys1 sed_test] for i in ${my_day[*]};do echo $i;done  
ha
wu
he
id
[dayuanshuai@idys1 sed_test] for i in ${my_day[@]};do echo $i;done
ha
wu
he
id
[dayuanshuai@idys1 sed_test] for i in "${my_day[@]}";do echo $i;done
ha
wu
he
id
[dayuanshuai@idys1 sed_test] for i in "${my_day[*]}";do echo $i;done 
ha wu he id

# 销毁前面一个数组,然后重新定义数组
[dayuanshuai@idys1 sed_test] unset  my_day
[dayuanshuai@idys1 sed_test] echo ${my_day[@]}
[dayuanshuai@idys1 sed_test] my_day=([0]="hello world" [1]="mysql" [2]="hei you")

# 可以看到加了 双引号 与没加双引号输出的区别, for in 时候,如果没有加双引号会以空格为分割
[dayuanshuai@idys1 sed_test] for i in ${my_day[@]};do echo $i;done
hello
world
mysql
hei
you
[dayuanshuai@idys1 sed_test] for i in "${my_day[@]}";do echo $i;done
hello world
mysql
hei you

# 打印数组所有下标元素
[dayuanshuai@idys1 sed_test] echo ${!my_day[@]}
0 1 2

# 给数组 添加元素
[dayuanshuai@idys1 sed_test] my_day+=("spanning tree")

# 打印所有下标元素
[dayuanshuai@idys1 sed_test] echo ${!my_day[@]}
0 1 2 3

# 取消数组下标元素。然后打印数组所有下标
[dayuanshuai@idys1 sed_test] unset my_day[0]
[dayuanshuai@idys1 sed_test] echo ${!my_day[@]}
1 2 3
  • 字符串判断
# 判断 test_str 变量
[dayuanshuai@idys1 sed_test] [ -z "$test_str" ] && echo "yes" || echo "no"  
no
[dayuanshuai@idys1 sed_test] [ -z $test_str ] && echo "yes" || echo "no"  
no

# 这个就不是判断变量了
[dayuanshuai@idys1 sed_test] [ -z test_str ] && echo "yes" || echo "no" 
no
[dayuanshuai@idys1 sed_test] [ -z who ] && echo "yes" || echo "no"        
no

# 这是是判断 变量是否为空
[dayuanshuai@idys1 sed_test] [ -z $who ] && echo "yes" || echo "no"
yes
[dayuanshuai@idys1 sed_test] [ -z "$who" ] && echo "yes" || echo "no" 
yes

# 判断两个元素是否相等。如果相等,那么则 打印 yes; 如果不等 则 打印 no
[dayuanshuai@idys1 sed_test] aa=11
[dayuanshuai@idys1 sed_test] bb=11
[dayuanshuai@idys1 sed_test] [ $aa == $bb ] && echo "yes" || echo "no"
yes
[dayuanshuai@idys1 sed_test] [ $aa == "11" ] && echo "yes" || echo "no"   
yes
[dayuanshuai@idys1 sed_test] [ $aa == "1" ] && echo "yes" || echo "no" 
no

3.6 多重条件判断

测试选项含义
判断 1 -a 判断 2逻辑与,判断 1 和判断 2 都成立,最终的结果才为真
判断 1 -o 判断 2逻辑或,判断 1 和判断 2 有一个成立,最终的结果就为真
!判断逻辑非,使原始的判断式取反
  • 逻辑与演示
# num1 的值为 22
[dayuanshuai@idys1 day6] num1=22
[dayuanshuai@idys1 day6] [ -n "$num1" -a "$num1" -gt 34 ] && echo yes || echo no
no
[dayuanshuai@idys1 day6] [ -n $num1 -a $num1 -gt 34 ] && echo yes || echo no    
no
# 判断 num1 的值是否不会空, 且是否大于1
[dayuanshuai@idys1 day6] [ -n $num1 -a $num1 -gt 1 ] && echo yes || echo no  
yes
  • 逻辑非演示
# -n 判断是否不会空 ! 非  组合起来就是 判断是否为空
[dayuanshuai@idys1 day6] [ ! -n $num ] && echo yes || echo no
no


注意:”和-n之间必须加入空格,否则会报错的。


04. 流程控制

4.1 if 条件判断

  1. 单分支 if 条件语句
  • 单分支条件语句最为简单,就是只有一个判断条件,如果符合条件则执行某个程序,否则什么事 情都不做。语法如下
if [ 条件判断式 ];then
程序
fi
  • 单分支条件语句需要注意几个点:
    • if 语句使用 fi 结尾,和一般语言使用大括号结尾不同
    • [ 条件判断式 ]就是使用 test 命令判断,所以中括号和条件判断式之间必须有空格
    • then 后面跟符合条件之后执行的程序,可以放在[]之后,用;分割。也可以换行写入, 就不需要;了,比如单分支 if 语句还可以这样写:
if [ 条件判断式 ]
	then
		程序
fi
  • 判断磁盘使用率。如果有磁盘的使用率超过 10%,那么就输出
# awk 做法
# df -h 查看磁盘使用信息
# sed 去掉使用率前面的 %
# awk 进行判断
[dayuanshuai@idys1 day6] df -h | sed "s/%//g"  | awk 'NR>1{if($5>10){printf("%-10s %i%\n",$1,$5)} }'
/dev/sda3  14%
/dev/sda1  20%

# 使用编程的做法
[dayuanshuai@idys1 day6] cat mytest.txt
#!/bin/bash

name=(`df -h | sed "1d" | awk '{print $1}'`)
value=(`df -h | sed "1d;s/%//g" | awk '{print $5}'`)
len=${#value[@]}

for((i=0;i<$len;i++));do
if [ ${value[$i]} -gt 10 ];then
echo "${name[$i]} used have more then 10%"
fi
done



  1. 双分支 if 条件语句
if [ 条件判断式 ]
then
	条件成立时,执行的程序
else
	条件不成立时,执行的另一个程序
fi
  • 例子1:初始化系统网络
#!/bin/bash

function network_init(){
alter_file=$1
dns1=$4
dns2=$5
i=3
network_area=$2
gateway=$3
sed -i 's/^BOOTPROTO=.*$/BOOTPROTO="static"/g' $alter_file
sed -i 's/^ONBOOT=.*$/ONBOOT="yes"/g' $alter_file
# if grep -i "^IPADDR=.*" ./ifcfg-ens32;then
#	sed -i "s/^IPADDR=.*/IPADDR=\"192.168.200.110\"/g" ./ifcfg-ens32
# else
# 	echo "IPADDR=\"192.168.200.110\"" >> ./ifcfg-ens32
# fi
while [ 1 ];do
if echo $network_area | grep -E "^(((\b[1-9]\b|\b[1-9][0-9]\b|\b1[0-9]{2}\b|\b2[0-4][0-9]\b|\b25[0-5]\b)\.){1}((\b[1-9]\b|\b[1-9]?[0-9]\b|\b1[0-9]{2}\b|\b2[0-4][0-9]\b|\b25[0-5]\b)\.){2}(\b[0-9]{1,2}\b|\b1[0-9]{2}\b|\b2[0-4][0-9]|\b|\b250))" >/dev/null 2>&1;then
	break
else
	echo -e "your input is error, please input again\n"
	read -p $'请输入所属该网段的IP\n' network_area
fi
done

network_area_pre=`echo $network_area | sed -r "s/\.[[:digit:]]{1,3}$//g"`

if ping -c 1 $network_area > /dev/null 2>&1;then
while [ $i -le 254 ]
do
if ping -c 1 $network_area_pre.$i > /dev/null 2>&1;then
    let i=i+1
else
    if grep -i "^IPADDR=.*" $alter_file >/dev/null 2>&1;then
        sed -i "s/^IPADDR=.*/IPADDR=\"192.168.200.$i\"/g" $alter_file
	else
	    echo "IPADDR=\"192.168.200.$i\"" >> $alter_file
	fi
break
fi
done
else
	sed -i "s/^IPADDR=.*/IPADDR=\"$network_area\"/g" $alter_file
fi

if grep -i "^PREFIX=.*" $alter_file >/dev/null;then
	sed -i "s/^PREFIX=.*/PREFIX=\"24\"/g" $alter_file
else 
	echo "PREFIX=\"24\"" >> $alter_file
fi
if grep -i "^GATEWAY=.*" $alter_file >/dev/null;then
        sed -i "s/^GATEWAY=.*/GATEWAY=\"$gateway\"/g" $alter_file
else
        echo "GATEWAY=\"$gateway\"" >> $alter_file
fi
if grep -i "^DNS1=.*" $alter_file > /dev/null;then
    sed -i "s/^DNS1=.*/DNS1=\"$dns1\"/g" $alter_file
else
   echo "DNS1=\"$dns1\"" >> $alter_file
fi
if grep -i "^DNS2=.*" $alter_file > /dev/null;then
    sed -i "s/^DNS2=.*/DNS2=\"$dns2\"/g" $alter_file
else
   echo "DNS2=\"$dns2\"" >> $alter_file
fi

}

function input_pra(){
read -p "请输入IP地址" ipaddr
while [ 1 ];do
if echo $ipaddr | grep -E "^(((\b[1-9]\b|\b[1-9][0-9]\b|\b1[0-9]{2}\b|\b2[0-4][0-9]\b|\b25[0-5]\b)\.){1}((\b[1-9]\b|\b[1-9]?[0-9]\b|\b1[0-9]{2}\b|\b2[0-4][0-9]\b|\b25[0-5]\b)\.){2}(\b[0-9]{1,2}\b|\b1[0-9]{2}\b|\b2[0-4][0-9]|\b|\b250))" >/dev/null 2>&1;then
	break
else
	echo -e "your input is error, please input again\n"
	read -p $'请输入所属该网段的IP\n' ipaddr
fi
done

read -p "请输入网关地址"  gateway
while [ 1 ];do
gateway_head=`echo $gateway | grep  -Eo  "(([[:digit:]]*)\.)*"`
ipaddr_head=`echo $ipaddr | grep  -Eo  "(([[:digit:]]*)\.)*"`
if echo $gateway | grep -E "^(((\b[1-9]\b|\b[1-9][0-9]\b|\b1[0-9]{2}\b|\b2[0-4][0-9]\b|\b25[0-5]\b)\.){1}((\b[1-9]\b|\b[1-9]?[0-9]\b|\b1[0-9]{2}\b|\b2[0-4][0-9]\b|\b25[0-5]\b)\.){2}(\b[0-9]{1,2}\b|\b1[0-9]{2}\b|\b2[0-4][0-9]|\b|\b250))" >/dev/null 2>&1;then
if [ $gateway_head == $ipaddr_head ];then
	break
else
	echo -e "your input is error, please input again\n"
	read -p $'请输入网关地址\n' gateway
fi
else
	echo -e "your input is error, please input again\n"
	read -p $'请输入网关地址\n' gateway
fi
done


read -p "请输入DNS1" dns1
while [ 1 ];do
if echo $dns1 | grep -E "^(((\b[1-9]\b|\b[1-9][0-9]\b|\b1[0-9]{2}\b|\b2[0-4][0-9]\b|\b25[0-5]\b)\.){1}((\b[1-9]\b|\b[1-9]?[0-9]\b|\b1[0-9]{2}\b|\b2[0-4][0-9]\b|\b25[0-5]\b)\.){2}(\b[0-9]{1,2}\b|\b1[0-9]{2}\b|\b2[0-4][0-9]|\b|\b250))" >/dev/null 2>&1;then
	break
else
	echo -e "your input is error, please input again\n"
	read -p $'请输入DNS1\n' dns1
fi
done

read -p "请输入DNS2" dns2
while [ 1 ];do
if echo $dns2 | grep -E "^(((\b[1-9]\b|\b[1-9][0-9]\b|\b1[0-9]{2}\b|\b2[0-4][0-9]\b|\b25[0-5]\b)\.){1}((\b[1-9]\b|\b[1-9]?[0-9]\b|\b1[0-9]{2}\b|\b2[0-4][0-9]\b|\b25[0-5]\b)\.){2}(\b[0-9]{1,2}\b|\b1[0-9]{2}\b|\b2[0-4][0-9]|\b|\b250))" >/dev/null 2>&1;then
	break
else
	echo -e "your input is error, please input again\n"
	read -p $'请输入DNS2\n' dns2
fi
done

network_init "./ifcfg-ens32" $ipaddr $gateway $dns1 $dns2
}

input_pra
  • 例子2:备份数据库
#!/bin/bash
#备份 mysql 数据库。
ntpdate asia.pool.ntp.org &>/dev/null
#同步系统时间
date=$(date +%y%m%d)
#把当前系统时间按照“年月日”格式赋予变量 date
size=$(du -sh /var/lib/mysql)
#统计 mysql 数据库的大小,并把大小赋予 size 变量
if [ -d /tmp/dbbak ]
#判断备份目录是否存在,是否为目录
	then
		#如果判断为真,执行以下脚本
 		echo "Date : $date!" > /tmp/dbbak/dbinfo.txt
		#把当前日期写入临时文件
		echo "Data size : $size" >> /tmp/dbbak/dbinfo.txt
		#把数据库大小写入临时文件
		cd /tmp/dbbak
		#进入备份目录
		tar -zcf mysql-lib-$date.tar.gz /var/lib/mysql dbinfo.txt &>/dev/null
		#打包压缩数据库与临时文件,把所有输出丢入垃圾箱(不想看到任何输出)
		rm -rf /tmp/dbbak/dbinfo.txt
		#删除临时文件
else
 mkdir /tmp/dbbak
#如果判断为假,则建立备份目录
 echo "Date : $date!" > /tmp/dbbak/dbinfo.txt
 echo "Data size : $size" >> /tmp/dbbak/dbinfo.txt
#把日期和数据库大小保存如临时文件
 cd /tmp/dbbak
 tar -zcf mysql-lib-$date.tar.gz dbinfo.txt /var/lib/mysql &>/dev/null
#压缩备份数据库与临时文件
 rm -rf /tmp/dbbak/dbinfo.txt
#删除临时文件
fi
  • 例子2:再举个例子,在工作当中,服务器上的服务经常会宕机。如果我们对服务器监控不好,就会造成 服务器中服务宕机了,而管理员却不知道的情况,这时我们可以写一个脚本来监听本机的服务,如果服务停止或宕机了,可以自动重启这些服务。我们拿 apache 服务来举例:
#!/bin/bash
#判断 apache 是否启动,如果没有启动则自动启动
port=$(nmap -sT 192.168.4.210 | grep tcp | grep http | awk '{print $2}')
#使用 nmap 命令扫描服务器,并截取 apache 服务的状态,赋予变量 port
if [ "$port" == "open" ]
#如果变量 port 的值是“open”
then
	echo$(date) httpd is ok!>> /tmp/autostart-acc.log
	#则证明 apache 正常启动,在正常日志中写入一句话即可
else
	/etc/rc.d/init.d/httpd start &>/dev/null
	#否则证明 apache 没有启动,自动启动 apache
	echo "$(date) restart httpd !!" >> /tmp/autostart-err.log
	#并在错误日志中记录自动启动 apche 的时间
fi

  1. nmap命令的使用
  • 用法格式
    • nmap [Scan Type...] [Options] {target specification}
  • 选项:
选项含义
-s扫描
-T扫描所有开启的 TCP 端口
-v显示详细信息
-p(rang),如-p20-120定义扫描的端口为20120-p23,80:扫描2380端口自定义端口范围
-sPnmap可以利用类似windows/linux系统下的ping 方式进行扫描
--traceroute路由器追踪功能
  • 扫描百度开放的端口
[root@idys ~] nmap -sT baidu.com

Starting Nmap 6.40 ( http://nmap.org ) at 2020-08-25 11:23 CST
Nmap scan report for baidu.com (39.156.69.79)
Host is up (0.036s latency).
Not shown: 996 filtered ports
PORT    STATE SERVICE
25/tcp  open  smtp
80/tcp  open  http
110/tcp open  pop3
443/tcp open  https

# 查看 http端口是否开发
[root@idys ~] nmap -sT 120.79.167.129 | grep http | awk '{print $2}'
Nmap
open
  1. 多分支 if 条件语句
if [ 条件判断式 1 ]
	then
	当条件判断式 1 成立时,执行程序 1
elif [ 条件判断式 2 ]
	then
	当条件判断式 2 成立时,执行程序 2
	…省略更多条件…
else
当所有条件都不成立时,最后执行此程序
fi
  • 一些题外话
    • find 用 扩展正则表达式
    • -regextype 'posix-egrep' -regex '扩展正则表达式'
  • sleep
  • 选项:
    • number : 时间长度,后面可接 smhd
    • 其中 s 为秒,m 为 分钟,h 为小时,d 为日数
# 暂停 4s 钟表
[root@idys ~] sleep 4
[root@idys ~] 

# 暂停 4 分钟
[root@idys ~] sleep 4m

# 实现加载 效果
[root@idys ~] for((i=0;i<4;i++));do echo -n ".";sleep 1;done;echo ""
....
  • paste
    • -d:指定分隔符
    • -s:多行变为一行,以每个文件为一个处理单元
[dayuanshuai@idys day03_sh] cat a.txt 
1
2
3
4
5
6
7
8
9
10

[dayuanshuai@idys day03_sh] cat b.txt 
a
b
c
d
e
f
g
h
i
j

[dayuanshuai@idys day03_sh] cat c.txt 
11
12
13
14
15
16
17
18
19
20

[dayuanshuai@idys day03_sh] paste a.txt b.txt c.txt 
1       a       11
2       b       12
3       c       13
4       d       14
5       e       15
6       f       16
7       g       17
8       h       18
9       i       19
10      j       20

# 多行变为一行,以 \t 分隔
[dayuanshuai@idys day03_sh] paste -s a.txt 
1       2       3       4       5       6       7       8       9       10
[dayuanshuai@idys day03_sh] paste -s a.txt b.txt 
1       2       3       4       5       6       7       8       9       10
a       b       c       d       e       f       g       h       i       j
[dayuanshuai@idys day03_sh] paste -s a.txt b.txt  c.txt 
1       2       3       4       5       6       7       8       9       10
a       b       c       d       e       f       g       h       i       j
11      12      13      14      15      16      17      18      19      20

[dayuanshuai@idys day03_sh] paste -d '-' -s a.txt 
1-2-3-4-5-6-7-8-9-10

[dayuanshuai@idys day03_sh] paste -d '-' a.txt b.txt 
1-a
2-b
3-c
4-d
5-e
6-f
7-g
8-h
9-i
10-j

[dayuanshuai@idys day03_sh] paste -d '-' -s a.txt b.txt 
1-2-3-4-5-6-7-8-9-10
a-b-c-d-e-f-g-h-i-j
  • tr命令:用于转换或删除文件中的字符
  • 语法
tr [-cdst][--help][--version][第一字符集][第二字符集]  
tr [OPTION]…SET1[SET2] 
  • -c, --complement:反选设定字符。也就是符合 SET1 的部份不做处理,不符合的剩余部份才进行转换
  • -d, --delete:删除指令字符
  • -s, --squeeze-repeats:缩减连续重复的字符成指定的单个字符
  • -t, --truncate-set1:削减 SET1 指定范围,使之与 SET2 设定长度相等
  • --help:显示程序用法信息
  • --version:显示程序本身的版本信息

字符集合的范围:

  • \NNN 八进制值的字符 NNN (1to 3 为八进制值的字符)
  • \\ 反斜杠
  • \a Ctrl-G 铃声
  • \b Ctrl-H 退格符
  • \f Ctrl-L 走行换页
  • \n Ctrl-J 新行
  • \r Ctrl-M 回车
  • \t Ctrl-I tab
  • \v Ctrl-X 水平制表符
  • CHAR1-CHAR2 :字符范围从 CHAR1CHAR2 的指定,范围的指定以 ASCII 码的次序为基础,只能由小到大,不能由大到小。
  • [CHAR*] :这是 SET2 专用的设定,功能是重复指定的字符到与 SET1 相同长度为止
  • [CHAR*REPEAT]:这也是 SET2专用的设定,功能是重复指定的字符到设定的 REPEAT 次数为止(REPEAT 的数字采 8 进位制计算,以 0 为开始)
  • [:alnum:]:所有字母字符与数字
  • [:alpha:]:所有字母字符
  • [:blank:] :所有水平空格
  • [:cntrl:] :所有控制字符
  • [:digit:]:所有数字
  • [:graph:] :所有可打印的字符(不包含空格符)
  • [:lower:]:所有小写字母
  • [:print:] :所有可打印的字符(包含空格符)
  • [:punct:] :所有标点字符
  • [:space:] :所有水平与垂直空格符
  • [:upper:]:所有大写字母
  • [:xdigit:]:所有 16进位制的数字
  • [=CHAR=] :所有符合指定的字符(等号里的CHAR,代表你可自订的字符)

  • 演示:tr 实现将小写字母替换为大写字母
[dayuanshuai@idys day03_sh] cat mytext.txt 
how are you 
please 
thank you 
me me and you 
ok ok haha
H W o kw
HOW br br br PO PO PO 
ksks W l LS nj
[dayuanshuai@idys day03_sh] cat mytext.txt | tr "a-z" "A-Z"
HOW ARE YOU 
PLEASE 
THANK YOU 
ME ME AND YOU 
OK OK HAHA
H W O KW
HOW BR BR BR PO PO PO 
KSKS W L LS NJ

[dayuanshuai@idys day03_sh] cat mytext.txt | tr [:lower:] [:upper:]
HOW ARE YOU 
PLEASE 
THANK YOU 
ME ME AND YOU 
OK OK HAHA
H W O KW
HOW BR BR BR PO PO PO 
KSKS W L LS NJ

[dayuanshuai@idys day03_sh] cat mytext.txt 
how 10 are you 
12 please 
thank 3 you 
me me 2 and you 
ok ok 2  haha 1
H W 78  12 o kw 189 
HOW br 56 12 br br PO PO PO 
ksks 12 W l LS nj

# 删除文本里面的数字
[dayuanshuai@idys day03_sh] cat mytext.txt | tr -d '0-9'
how  are you 
 please 
thank  you 
me me  and you 
ok ok   haha 
H W    o kw  
HOW br   br br PO PO PO 
ksks  W l LS nj

# 将空格转化为 制表符
[dayuanshuai@idys day03_sh] cat mytext.txt | tr " " "\t"
how     10      are     you
12      please
thank   3       you
me      me      2       and     you
ok      ok      2               haha    1
H       W       78              12      o       kw      189
HOW     br      56      12      br      br      PO      PO      PO
ksks    12      W       l       LS      nj

# 反选匹配到的字符, 如果匹配到的字符 就不做处理。 没有匹配到的字符就处理 -d 是删除的意思
[dayuanshuai@idys day03_sh] cat mytext.txt | tr -d -c "1-9 \n how"
how 1  o 
12  
h 3 o 
  2  o 
o o 2  hh 1
  78  12 o w 189 
  56 12      
 12 

[dayuanshuai@idys day03_sh] cat mytext.txt 
how 10 are you 
12 please 
thank 3 you 
me me 2 and you 
ok ok 2  haha 1
H W 78  12 o kw 189 
HOW br 56 12 br br PO PO PO 
ksks 12 W l LS nj
who wwwwwww sssss
bbbbbb kkkkk qqqqq ooooo sssss vvvv

# 删减重复的字符 ,字符里面包括 b k q o s w v
[dayuanshuai@idys day03_sh] cat mytext.txt | tr -s "b k q o s w v"
how 10 are you 
12 please 
thank 3 you 
me me 2 and you 
ok ok 2 haha 1
H W 78 12 o kw 189 
HOW br 56 12 br br PO PO PO 
ksks 12 W l LS nj
who w s
b k q o s v

[dayuanshuai@idys ~] seq 6 12
6
7
8
9
10
11
12

[dayuanshuai@idys ~] seq 6 12
6
7
8
9
10
11
12

# tr 命令 实现数字加减
[dayuanshuai@idys ~] seq 6 12 | echo $[ $(tr "\n" "+")0 ]
63

# 生产固定长度的随机数密码
[dayuanshuai@idys day03_sh] head /dev/urandom | tr -dc A-Za-z0-9 | head -c 20;echo ""
0fUqCj7GXHaiYuAXENGM

  • if多分支条件语句演示,查找所有的压缩文件,并且按照编号对压缩文件进行编号。同时选择某个编号的时候,可以打印出编号对应的压缩文件
  • 代码演示
#!/bin/bash
function my_select(){
array=(`find / -type f  -iname "*.tar" -o -iname "*.zip" -o -name "*.rar" -o -iname "*.gzip" -o -iname "*.iso" -o -iname "*.tar.gz" -o -iname "*.gz" `)  # you can select command find or locate, command locate is efficient, but it is inaccurate. so I select command find.
while [ 1 ];do
read -p "first, the program be display is similar to less,when you read , you used comamnd as less, if you know [Y/N]" judge
if [ $judge == "Y" -o $judge == "y" ];then
break
fi
done


while [ 1 ];do for i in ${!array[@]};do printf "%-6i ------------------->  %-50s\n" $((i+1)) ${array[$i]};done | less ;read -p $'please input num to choice file \n ---------->' num;if [ -z $num ];then echo -e "because you input is null, the system is default choice\n----------------->  ${array[0]}";break;elif echo $num | grep -E '[^[:digit:]]';then echo -e "yur input is contain other char,please input again";echo -e "because your input is error, please wait 10 second \n";for((i=0;i<10;i++));do echo -n "* ";sleep 1;done;echo -e "\n";elif [ $num -gt ${#array[@]} ];then echo -e "\nyou input num more than the total of compressed file,the operation is error\n";echo -e "because your input is error, please wait 10second\n";for((i=0;i<10;i++));do echo -n "* ";sleep 1;done;echo -e "\n";else echo "your choice file is ---------------->  ${array[$((num-1))]}";break;fi;done
}
my_select
  • 运行结果
# 第一次 测试

[root@idys ~] bash mytest.sh
first, the program be display is similar to less,when you read , you used comamnd as less, if you know [Y/N]Y
1      ------------------->  /boot/grub/splash.xpm.gz                          
2      ------------------->  /boot/symvers-3.10.0-1062.el7.x86_64.gz           
3      ------------------->  /root/testnet.sh.gz                               
4      ------------------->  /var/cache/yum/x86_64/7/base/a4e2b46586aa556c3b6f814dad5b16db5a669984d66b68e873586cd7c7253301-c7-x86_64-comps.xml.gz
5      ------------------->  /var/cache/yum/x86_64/7/c7-media/4af1fba0c1d6175b7e3c862b4bddfef93fffb84c37f7d5f18cfbff08abc47f8a-c7-x86_64-comps.xml.gz
6      ------------------->  /var/cache/yum/x86_64/7/CentOS7/4af1fba0c1d6175b7e3c862b4bddfef93fffb84c37f7d5f18cfbff08abc47f8a-c7-x86_64-comps.xml.gz
7      ------------------->  /tmp/day01_sh.tar                                 
8      ------------------->  /usr/lib/kbd/consolefonts/gr928a-8x16.psfu.gz     
9      ------------------->  /usr/lib/kbd/consolefonts/161.cp.gz               
10     ------------------->  /usr/lib/kbd/consolefonts/gr928b-8x14.psfu.gz     
11     ------------------->  /usr/lib/kbd/consolefonts/162.cp.gz               
12     ------------------->  /usr/lib/kbd/consolefonts/gr928b-8x16.psfu.gz     
13     ------------------->  /usr/lib/kbd/consolefonts/163.cp.gz               
14     ------------------->  /usr/lib/kbd/consolefonts/iso01-12x22.psfu.gz     
15     ------------------->  /usr/lib/kbd/consolefonts/164.cp.gz               
16     ------------------->  /usr/lib/kbd/consolefonts/iso01.14.gz             
17     ------------------->  /usr/lib/kbd/consolefonts/165.cp.gz               
18     ------------------->  /usr/lib/kbd/consolefonts/iso01.08.gz             
19     ------------------->  /usr/lib/kbd/consolefonts/737.cp.gz               
20     ------------------->  /usr/lib/kbd/consolefonts/iso01.16.gz             
21     ------------------->  /usr/lib/kbd/consolefonts/880.cp.gz               
22     ------------------->  /usr/lib/kbd/consolefonts/iso02.14.gz             
23     ------------------->  /usr/lib/kbd/consolefonts/928.cp.gz               
24     ------------------->  /usr/lib/kbd/consolefonts/iso02-12x22.psfu.gz     
25     ------------------->  /usr/lib/kbd/consolefonts/972.cp.gz               
26     ------------------->  /usr/lib/kbd/consolefonts/cybercafe.fnt.gz        
27     ------------------->  /usr/lib/kbd/consolefonts/Agafari-12.psfu.gz      
28     ------------------->  /usr/lib/kbd/consolefonts/cyr-sun16.psfu.gz       
29     ------------------->  /usr/lib/kbd/consolefonts/Agafari-14.psfu.gz      
30     ------------------->  /usr/lib/kbd/consolefonts/default8x16.psfu.gz     
31     ------------------->  /usr/lib/kbd/consolefonts/Agafari-16.psfu.gz      
32     ------------------->  /usr/lib/kbd/consolefonts/default8x9.psfu.gz      
33     ------------------->  /usr/lib/kbd/consolefonts/Cyr_a8x14.psfu.gz       
34     ------------------->  /usr/lib/kbd/consolefonts/drdos8x14.psfu.gz       
35     ------------------->  /usr/lib/kbd/consolefonts/Cyr_a8x16.psfu.gz       
36     ------------------->  /usr/lib/kbd/consolefonts/drdos8x16.psfu.gz       
37     ------------------->  /usr/lib/kbd/consolefonts/Cyr_a8x8.psfu.gz        
38     ------------------->  /usr/lib/kbd/consolefonts/iso02.08.gz             
39     ------------------->  /usr/lib/kbd/consolefonts/drdos8x6.psfu.gz        
40     ------------------->  /usr/lib/kbd/consolefonts/Goha-12.psfu.gz         
41     ------------------->  /usr/lib/kbd/consolefonts/drdos8x8.psfu.gz        
42     ------------------->  /usr/lib/kbd/consolefonts/Goha-14.psfu.gz         
43     ------------------->  /usr/lib/kbd/consolefonts/eurlatgr.psfu.gz        
44     ------------------->  /usr/lib/kbd/consolefonts/Goha-16.psfu.gz         
45     ------------------->  /usr/lib/kbd/consolefonts/UniCyr_8x16.psf.gz      
46     ------------------->  /usr/lib/kbd/consolefonts/GohaClassic-12.psfu.gz  
47     ------------------->  /usr/lib/kbd/consolefonts/UniCyr_8x8.psf.gz       
48     ------------------->  /usr/lib/kbd/consolefonts/GohaClassic-14.psfu.gz  
49     ------------------->  /usr/lib/kbd/consolefonts/alt-8x14.gz             
50     ------------------->  /usr/lib/kbd/consolefonts/iso05.08.gz             
51     ------------------->  /usr/lib/kbd/consolefonts/GohaClassic-16.psfu.gz  
52     ------------------->  /usr/lib/kbd/consolefonts/alt-8x16.gz             
53     ------------------->  /usr/lib/kbd/consolefonts/iso05.14.gz             
54     ------------------->  /usr/lib/kbd/consolefonts/Lat2-Terminus16.psfu.gz 
55     ------------------->  /usr/lib/kbd/consolefonts/alt-8x8.gz              
56     ------------------->  /usr/lib/kbd/consolefonts/iso05.16.gz             
57     ------------------->  /usr/lib/kbd/consolefonts/LatArCyrHeb-08.psfu.gz  
58     ------------------->  /usr/lib/kbd/consolefonts/aply16.psf.gz           
59     ------------------->  /usr/lib/kbd/consolefonts/LatArCyrHeb-14.psfu.gz  
60     ------------------->  /usr/lib/kbd/consolefonts/altc-8x16.gz            
61     ------------------->  /usr/lib/kbd/consolefonts/iso06.08.gz             
62     ------------------->  /usr/lib/kbd/consolefonts/LatArCyrHeb-16+.psfu.gz 
63     ------------------->  /usr/lib/kbd/consolefonts/arm8.fnt.gz             
64     ------------------->  /usr/lib/kbd/consolefonts/iso06.14.gz             
65     ------------------->  /usr/lib/kbd/consolefonts/LatArCyrHeb-16.psfu.gz  
66     ------------------->  /usr/lib/kbd/consolefonts/cp1250.psfu.gz          
67     ------------------->  /usr/lib/kbd/consolefonts/LatArCyrHeb-19.psfu.gz  
68     ------------------->  /usr/lib/kbd/consolefonts/cp850-8x14.psfu.gz      
69     ------------------->  /usr/lib/kbd/consolefonts/LatGrkCyr-12x22.psfu.gz 
70     ------------------->  /usr/lib/kbd/consolefonts/cp850-8x16.psfu.gz      
71     ------------------->  /usr/lib/kbd/consolefonts/LatGrkCyr-8x16.psfu.gz  
72     ------------------->  /usr/lib/kbd/consolefonts/gr737b-9x16-medieval.psfu.gz
73     ------------------->  /usr/lib/kbd/consolefonts/LatKaCyrHeb-14.psfu.gz  
74     ------------------->  /usr/lib/kbd/consolefonts/iso02.16.gz             
please input num to choice file 
 ---------->45
your choice file is ---------------->  /usr/lib/kbd/consolefonts/UniCyr_8x16.psf.gz

# 第二次测试
[root@idys ~] bash mytest.sh
first, the program be display is similar to less,when you read , you used comamnd as less, if you know [Y/N]Y
1      ------------------->  /boot/grub/splash.xpm.gz                          
2      ------------------->  /boot/symvers-3.10.0-1062.el7.x86_64.gz           
3      ------------------->  /root/testnet.sh.gz                               
4      ------------------->  /var/cache/yum/x86_64/7/base/a4e2b46586aa556c3b6f814dad5b16db5a669984d66b68e873586cd7c7253301-c7-x86_64-comps.xml.gz
5      ------------------->  /var/cache/yum/x86_64/7/c7-media/4af1fba0c1d6175b7e3c862b4bddfef93fffb84c37f7d5f18cfbff08abc47f8a-c7-x86_64-comps.xml.gz
6      ------------------->  /var/cache/yum/x86_64/7/CentOS7/4af1fba0c1d6175b7e3c862b4bddfef93fffb84c37f7d5f18cfbff08abc47f8a-c7-x86_64-comps.xml.gz
7      ------------------->  /tmp/day01_sh.tar                                 
8      ------------------->  /usr/lib/kbd/consolefonts/gr928a-8x16.psfu.gz     
9      ------------------->  /usr/lib/kbd/consolefonts/161.cp.gz               
10     ------------------->  /usr/lib/kbd/consolefonts/gr928b-8x14.psfu.gz     
11     ------------------->  /usr/lib/kbd/consolefonts/162.cp.gz               
12     ------------------->  /usr/lib/kbd/consolefonts/gr928b-8x16.psfu.gz     
13     ------------------->  /usr/lib/kbd/consolefonts/163.cp.gz               
14     ------------------->  /usr/lib/kbd/consolefonts/iso01-12x22.psfu.gz     
15     ------------------->  /usr/lib/kbd/consolefonts/164.cp.gz               
16     ------------------->  /usr/lib/kbd/consolefonts/iso01.14.gz             
17     ------------------->  /usr/lib/kbd/consolefonts/165.cp.gz               
18     ------------------->  /usr/lib/kbd/consolefonts/iso01.08.gz             
19     ------------------->  /usr/lib/kbd/consolefonts/737.cp.gz               
20     ------------------->  /usr/lib/kbd/consolefonts/iso01.16.gz             
21     ------------------->  /usr/lib/kbd/consolefonts/880.cp.gz               
22     ------------------->  /usr/lib/kbd/consolefonts/iso02.14.gz             
23     ------------------->  /usr/lib/kbd/consolefonts/928.cp.gz               
24     ------------------->  /usr/lib/kbd/consolefonts/iso02-12x22.psfu.gz     
25     ------------------->  /usr/lib/kbd/consolefonts/972.cp.gz               
26     ------------------->  /usr/lib/kbd/consolefonts/cybercafe.fnt.gz        
27     ------------------->  /usr/lib/kbd/consolefonts/Agafari-12.psfu.gz      
28     ------------------->  /usr/lib/kbd/consolefonts/cyr-sun16.psfu.gz       
29     ------------------->  /usr/lib/kbd/consolefonts/Agafari-14.psfu.gz      
30     ------------------->  /usr/lib/kbd/consolefonts/default8x16.psfu.gz     
please input num to choice file 
 ---------->1000000

you input num more than the total of compressed file,the operation is error

because your input is error, please wait 10second

* * * * * * * * * * 

1      ------------------->  /boot/grub/splash.xpm.gz                          
2      ------------------->  /boot/symvers-3.10.0-1062.el7.x86_64.gz           
3      ------------------->  /root/testnet.sh.gz                               
4      ------------------->  /var/cache/yum/x86_64/7/base/a4e2b46586aa556c3b6f814dad5b16db5a669984d66b68e873586cd7c7253301-c7-x86_64-comps.xml.gz
5      ------------------->  /var/cache/yum/x86_64/7/c7-media/4af1fba0c1d6175b7e3c862b4bddfef93fffb84c37f7d5f18cfbff08abc47f8a-c7-x86_64-comps.xml.gz
6      ------------------->  /var/cache/yum/x86_64/7/CentOS7/4af1fba0c1d6175b7e3c862b4bddfef93fffb84c37f7d5f18cfbff08abc47f8a-c7-x86_64-comps.xml.gz
7      ------------------->  /tmp/day01_sh.tar                                 
8      ------------------->  /usr/lib/kbd/consolefonts/gr928a-8x16.psfu.gz     
9      ------------------->  /usr/lib/kbd/consolefonts/161.cp.gz               
10     ------------------->  /usr/lib/kbd/consolefonts/gr928b-8x14.psfu.gz     
11     ------------------->  /usr/lib/kbd/consolefonts/162.cp.gz               
12     ------------------->  /usr/lib/kbd/consolefonts/gr928b-8x16.psfu.gz     
13     ------------------->  /usr/lib/kbd/consolefonts/163.cp.gz               
14     ------------------->  /usr/lib/kbd/consolefonts/iso01-12x22.psfu.gz     
15     ------------------->  /usr/lib/kbd/consolefonts/164.cp.gz               
16     ------------------->  /usr/lib/kbd/consolefonts/iso01.14.gz             
17     ------------------->  /usr/lib/kbd/consolefonts/165.cp.gz               
18     ------------------->  /usr/lib/kbd/consolefonts/iso01.08.gz             
19     ------------------->  /usr/lib/kbd/consolefonts/737.cp.gz               
20     ------------------->  /usr/lib/kbd/consolefonts/iso01.16.gz             
please input num to choice file 
 ---------->sdfsdf
sdfsdf
yur input is contain other char,please input again
because your input is error, please wait 10 second 

* * * * * * * * * * 

1      ------------------->  /boot/grub/splash.xpm.gz                          
2      ------------------->  /boot/symvers-3.10.0-1062.el7.x86_64.gz           
3      ------------------->  /root/testnet.sh.gz                               
4      ------------------->  /var/cache/yum/x86_64/7/base/a4e2b46586aa556c3b6f814dad5b16db5a669984d66b68e873586cd7c7253301-c7-x86_64-comps.xml.gz
5      ------------------->  /var/cache/yum/x86_64/7/c7-media/4af1fba0c1d6175b7e3c862b4bddfef93fffb84c37f7d5f18cfbff08abc47f8a-c7-x86_64-comps.xml.gz
6      ------------------->  /var/cache/yum/x86_64/7/CentOS7/4af1fba0c1d6175b7e3c862b4bddfef93fffb84c37f7d5f18cfbff08abc47f8a-c7-x86_64-comps.xml.gz
7      ------------------->  /tmp/day01_sh.tar                                 
8      ------------------->  /usr/lib/kbd/consolefonts/gr928a-8x16.psfu.gz     
9      ------------------->  /usr/lib/kbd/consolefonts/161.cp.gz               
10     ------------------->  /usr/lib/kbd/consolefonts/gr928b-8x14.psfu.gz     
11     ------------------->  /usr/lib/kbd/consolefonts/162.cp.gz               
12     ------------------->  /usr/lib/kbd/consolefonts/gr928b-8x16.psfu.gz     
13     ------------------->  /usr/lib/kbd/consolefonts/163.cp.gz               
14     ------------------->  /usr/lib/kbd/consolefonts/iso01-12x22.psfu.gz     
15     ------------------->  /usr/lib/kbd/consolefonts/164.cp.gz               
16     ------------------->  /usr/lib/kbd/consolefonts/iso01.14.gz             
17     ------------------->  /usr/lib/kbd/consolefonts/165.cp.gz               
18     ------------------->  /usr/lib/kbd/consolefonts/iso01.08.gz             
19     ------------------->  /usr/lib/kbd/consolefonts/737.cp.gz               
20     ------------------->  /usr/lib/kbd/consolefonts/iso01.16.gz             
21     ------------------->  /usr/lib/kbd/consolefonts/880.cp.gz               
22     ------------------->  /usr/lib/kbd/consolefonts/iso02.14.gz             
23     ------------------->  /usr/lib/kbd/consolefonts/928.cp.gz               
24     ------------------->  /usr/lib/kbd/consolefonts/iso02-12x22.psfu.gz     
25     ------------------->  /usr/lib/kbd/consolefonts/972.cp.gz               
26     ------------------->  /usr/lib/kbd/consolefonts/cybercafe.fnt.gz        
27     ------------------->  /usr/lib/kbd/consolefonts/Agafari-12.psfu.gz      
28     ------------------->  /usr/lib/kbd/consolefonts/cyr-sun16.psfu.gz       
29     ------------------->  /usr/lib/kbd/consolefonts/Agafari-14.psfu.gz      
30     ------------------->  /usr/lib/kbd/consolefonts/default8x16.psfu.gz     
31     ------------------->  /usr/lib/kbd/consolefonts/Agafari-16.psfu.gz      
32     ------------------->  /usr/lib/kbd/consolefonts/default8x9.psfu.gz      
please input num to choice file 
 ---------->12
your choice file is ---------------->  /usr/lib/kbd/consolefonts/gr928b-8x16.psfu.gz

  • 那我们再写一个例子,用 if 多分支条件语句来判断一下用户输入的是一个文件,还是一个目录
#!/bin/bash
# 判断用户输入的是什么文件
read -p "Please input a filename: " file
#接收键盘的输入,并赋予变量 file
if [ -z "$file" ]
#判断 file 变量是否为空
	then
		echo "Error,please input a filename"
		#如果为空,执行程序 1,也就是输出报错信息
		exit 1
		#退出程序,并返回值为 1(把返回值赋予变量$?)
elif [ ! -e "$file" ]
#判断 file 的值是否存在
	then
		echo "Your input is not a file!"
		#如果不存在,则执行程序 2
		exit 2
		#退出程序,把并定义返回值为 2
elif [ -f "$file" ]
#判断 file 的值是否为普通文件
	then
 		echo "$file is a regulare file!"
		#如果是普通文件,则执行程序 3
elif [ -d "$file" ]
	#判断 file 的值是否为目录文件
	then
		echo "$file is a directory!"
		#如果是目录文件,则执行程序 4
else
	echo "$file is an other file!"
	#如果以上判断都不是,则执行程序 5
fi

4.2 多分支 case 条件语句

  • case 语句和 if…elif…else 语句一样都是多分支条件语句,不过和 if多分支条件语句不同的是, case 语句只能判断一种条件关系,而 if 语句可以判断多种条件关系。case 语句语法如下
case $变量名 in
"值 1")
如果变量的值等于值 1,则执行程序 1
;;
"值 2")
如果变量的值等于值 2,则执行程序 2
;;
…省略其他分支…
*)
如果变量的值都不是以上的值,则执行此程序
;;
esac
  • 这个语句需要注意以下内容:

    • case 语句,会取出变量中的值,然后与语句体中的值逐一比较。如果数值符合,则执行对应的程序,如果数值不符,则依次比较下一个值。如果所有的值都不符合,则执行*) (* 代表所有其他值)中的程序
    • case 语句以case开头,以esac结尾。
  • 每一个分支程序之后要通过;;双分号结尾,代表该程序段结束

  • case语句综合应用

[dayuanshuai@idys day03_sh] cat system_menu.sh 
#!/bin/bash

function display_ip(){

ifconfig | grep "inet" | head -1| awk '{print $2}'

}

function display_disk(){

df -h | awk 'NR>=2{ printf "%-10s --------> %s\n",$1,$5 }'

}

function system_run(){

uptime  | awk -F '[ :,]' '{printf "your system have run %i hour %i minute\n",$6,$7}'

}

function system_display(){
cat << EOF
----------------------------------------
|*****************Menu******************|
----------------------------------------
`echo -e "\033[31m 1)display the left of disk space\033[0m"`
`echo -e "\033[32m 2)display IP address\033[0m"`
`echo -e "\033[33m 3)display system have run time\033[0m"`
EOF
read -p $'please input your num\n' num
case $num in
1)
   display_disk
;;
2)
display_ip
;;
3)
system_run
;;
*)
system_display
esac
}

system_display
  • 运行结果
[dayuanshuai@idys day03_sh] bash system_menu.sh 
----------------------------------------
|*****************Menu******************|
----------------------------------------
 1)display the left of disk space
 2)display IP address
 3)display system have run time
please input your num
2
192.168.200.143
[dayuanshuai@idys day03_sh] bash system_menu.sh 
----------------------------------------
|*****************Menu******************|
----------------------------------------
 1)display the left of disk space
 2)display IP address
 3)display system have run time
please input your num
3
your system have run 13 hour 39 minute
[dayuanshuai@idys day03_sh] bash system_menu.sh 
----------------------------------------
|*****************Menu******************|
----------------------------------------
 1)display the left of disk space
 2)display IP address
 3)display system have run time
please input your num
1
devtmpfs   --------> 0%
tmpfs      --------> 0%
tmpfs      --------> 1%
tmpfs      --------> 0%
/dev/sda2  --------> 6%
/dev/sr0   --------> 100%
/dev/sda1  --------> 56%
tmpfs      --------> 0%
tmpfs      --------> 0%

  • 一个简单的case 判断脚本
#!/bin/bash
#判断用户输入
read -p "Please choose yes/no: " -t 30 cho
#在屏幕上输出“请选择 yes/no”,然后把用户选择赋予变量 cho
case $cho in
#判断变量 cho 的值
"yes")
	#如果是 yes
	echo "Your choose is yes!"
	#执行程序 1
;;
"no")
	#如果是 no
	echo "Your choose is no!"	
	#执行程序 2
;;
*)
	#如果既不是 yes,也不是 no
	echo "Your choose is error!"
	#则执行此程序
;;
esac

4.3 for 循环

  • for 循环是固定循环,也就是在循环时已经知道需要进行几次的循环,有时也把 for 循环称为计数循环。for 的语法有如下两种:

  • 语言一:

for 变量 in 值 1 值 2 值 3…
do
程序
done
  • 这种语法中 for 循环的次数,取决于 in 后面值的个数(空格分隔),有几个值就循环几次,并且每次循环都把值赋予变量。也就是说,假设 in 后面有三个值,for 会循环三次,第一次循环会把值 1 赋予变量,第二次循环会把值 2 赋予变量,以此类推。

  • 语法二:
for (( 初始值;循环控制条件;变量变化 ))
do
程序
done
  • 语法二中需要注意:
    • 初始值:在循环开始时,需要给某个变量赋予初始值,如 i=1
    • 循环控制条件:用于指定变量循环的次数,如 i<=100,则只要 i 的值小于等于 100,循环就会继续;
    • 变量变化:每次循环之后,变量该如何变化,如 i=i+1。代表每次循环之后,变量 i 的值都 加 1

  • 语法一举例:
[root@idys ~]# for i in 1 2 3;do echo $i;done;
1
2
3
  • 或者这样也行
[dayuanshuai@idys day01_sh]$ cat for_one_type.sh 
# !/bin/bash
for i in 1 2 3
do
    echo $i
done
[dayuanshuai@idys day01_sh]$ chmod u+x for_one_type.sh 
[dayuanshuai@idys day01_sh]$ ./for_one_type.sh 
1
2
3
  • 实现批量解压压缩文件
[root@idys LAMP-php7] ls | tr " " "\n" | xargs -n1 -I {} tar -zxvf {}

  • 删除所有压缩文件
[root@idys LAMP-php7] ls ./*.gz | xargs -n 1 -I {} rm {}
  • 删除当前目录下所有的非*.gz*zip的文件
[root@idys LAMP-php7] ls  # 当前目录下有目录文件和压缩文件
apr-1.4.6              jpegsrc.v6b.tar.gz      memcached-1.4.17         pcre-8.34.tar.gz
apr-1.4.6.tar.gz       libmcrypt-2.5.8         memcached-1.4.17.tar.gz  pecl-memcache-php7.zip
apr-util-1.4.1         libmcrypt-2.5.8.tar.gz  mhash-0.9.9.9            php-7.0.7
apr-util-1.4.1.tar.gz  libpng-1.2.31           mhash-0.9.9.9.tar.gz     php-7.0.7.tar.gz
freetype-2.3.5         libpng-1.2.31.tar.gz    mysql-5.5.48             phpMyAdmin-4.1.4-all-languages
freetype-2.3.5.tar.gz  libxml2-2.9.1           mysql-5.5.48.tar.gz      phpMyAdmin-4.1.4-all-languages.tar.gz
httpd-2.4.7            libxml2-2.9.1.tar.gz    ncurses-5.9              zlib-1.2.3
httpd-2.4.7.tar.gz     mcrypt-2.6.8            ncurses-5.9.tar.gz       zlib-1.2.3.tar.gz
jpeg-6b                mcrypt-2.6.8.tar.gz     pcre-8.34
[root@idys LAMP-php7] ls --ignore="*.gz" --ignore="*.zip" | xargs -n1 -I {} rm -rf {}  # 现在删除当前目录下所有的目录文件
[root@idys LAMP-php7] ls
apr-1.4.6.tar.gz       libmcrypt-2.5.8.tar.gz   mhash-0.9.9.9.tar.gz    php-7.0.7.tar.gz
apr-util-1.4.1.tar.gz  libpng-1.2.31.tar.gz     mysql-5.5.48.tar.gz     phpMyAdmin-4.1.4-all-languages.tar.gz
freetype-2.3.5.tar.gz  libxml2-2.9.1.tar.gz     ncurses-5.9.tar.gz      zlib-1.2.3.tar.gz
httpd-2.4.7.tar.gz     mcrypt-2.6.8.tar.gz      pcre-8.34.tar.gz
jpegsrc.v6b.tar.gz     memcached-1.4.17.tar.gz  pecl-memcache-php7.zip
  • 解压当前目录下所有的压缩文件,并且查看是否执行成功
# 首先查看当前目录下的所有文件(含目录)
[root@idys LAMP-php7] ls
apr-1.4.6.tar.gz       libmcrypt-2.5.8.tar.gz   mhash-0.9.9.9.tar.gz    php-7.0.7.tar.gz
apr-util-1.4.1.tar.gz  libpng-1.2.31.tar.gz     mysql-5.5.48.tar.gz     phpMyAdmin-4.1.4-all-languages.tar.gz
freetype-2.3.5.tar.gz  libxml2-2.9.1.tar.gz     ncurses-5.9.tar.gz      zlib-1.2.3.tar.gz
httpd-2.4.7.tar.gz     mcrypt-2.6.8.tar.gz      pcre-8.34.tar.gz
jpegsrc.v6b.tar.gz     memcached-1.4.17.tar.gz  pecl-memcache-php7.zip
# 解压所有的压缩文件,并且不输出,最后echo $? 查看返回结果
[root@idys LAMP-php7] for i in `ls *gz`;do tar -zxvf $i >/dev/null 2>&1;done;unzip *.zip &>/dev/null;echo $?
0
  • for循环实现累加(1到100)
[dayuanshuai@idys day01_sh] cat for_two_typev1.sh 
# !/bin/bash

for((i=1;i<=100;i++))
do

let sum=sum+i

done
echo -n "sum="
for i in `seq 1 100`
do
   if [ $i -ge 100 ];then
    echo -n $i
   else
    echo -n "$i+"
   fi
done
echo  "=$sum"

[dayuanshuai@idys day01_sh] bash for_two_typev1.sh 
sum=1+2+3+4+5+6+7+8+9+10+11+12+13+14+15+16+17+18+19+20+21+22+23+24+25+26+27+28+29+30+31+32+33+34+35+36+37+38+39+40+41+42+43+44+45+46+47+48+49+50+51+52+53+54+55+56+57+58+59+60+61+62+63+64+65+66+67+68+69+70+71+72+73+74+75+76+77+78+79+80+81+82+83+84+85+86+87+88+89+90+91+92+93+94+95+96+97+98+99+100=5050

  • 批量添加用户
[root@idys day01_sh] vim useradd_username.sh
#让用户输入初始密码,把输入保存如变量 pass
if [ ! -z "$name" -a ! -z "$num" -a ! -z "$pass" ]
 fi
 done
# !/bin/bash

function useradd_username(){
read -p "Please input user name: " -t 60 name
#让用户输入用户名,把输入保存入变量 name
read -p "Please input the number of users: " -t 60 num
#让用户输入添加用户的数量,把输入保存入变量 num
read -p "Please input the password of users: " -t 60 pass
#让用户输入初始密码,把输入保存如变量 pass
if [ ! -z "$name" -a ! -z "$num" -a ! -z "$pass" ];then
if echo $num | grep "^[[:digit:]]$" >/dev/null 2>&1;then
for (( i=1;i<=$num;i=i+1 ))
      #循环 num 变量指定的次数
    do
      /usr/sbin/useradd $name$i &>/dev/null
      #添加用户,用户名为变量 name 的值加变量 i 的数字
      echo $pass | /usr/bin/passwd --stdin $name$i &>/dev/null
      #给用户设定初始密码为变量 pass 的值
    done
fi
fi
}

useradd_username
[root@idys day01_sh] bash useradd_username.sh 
Please input user name: idys
Please input the number of users: 4
Please input the password of users: 123456
[root@idys day01_sh] ls /home
dayuanshuai  idys1  idys2  idys3  idys4
[root@idys day01_sh] su - dayuanshuai
上一次登录:日 9月  6 17:40:47 CST 2020pts/1 上
[dayuanshuai@idys ~] su  - idys1
密码:
[idys1@idys ~] exit
登出
  • 批量删除用户
[root@idys day01_sh] ls /home
dayuanshuai  idys1  idys2  idys3  idys4
[root@idys day01_sh] cat /etc/passwd | grep /bin/bash | grep -vE "root|dayuanshuai" | awk -F ":" '{printf $1"\n"}'
idys1
idys2
idys3
idys4
[root@idys day01_sh] cat /etc/passwd | grep /bin/bash | grep -vE "root|dayuanshuai" | awk -F ":" '{printf $1"\n"}' | xargs -n1 -I {} userdel -r {}
[root@idys day01_sh] ls /home  # 现在可以看到所有的其他用户均删除了
dayuanshuai
[root@idys day01_sh] bash useradd_username.sh  # 再次添加用户
Please input user name: hanhan
Please input the number of users: 5
Please input the password of users: 123456

[root@idys day01_sh] for i in `cat /etc/passwd | grep /bin/bash | grep -vE "root|dayuanshuai" | awk -F ":" '{printf $1"\n"}'`;do userdel -r $i;done  #利用for循环删除其他用户

4.4 while 循环

  • while循环语法形式
while [ 条件判断式 ]
do
程序
done

对 while 循环来讲,只要条件判断式成立,循环就会一直继续,直到条件判断式不成立,循环才会停止。

  • 利用while循环,将一个数从1输出到100
[dayuanshuai@idys day01_sh] cat while_file.sh 
# !/bin/bash

function test_while(){
i=$1
k=0
while [ $i -le 100 ]
do
  echo -ne "$i\t"
  let i=i+1
  let k=k+1
  if [ $((k % 16)) -eq 0 ];then
  echo "" 
  fi
done
echo ""
}

test_while 1
[dayuanshuai@idys day01_sh] bash while_file.sh 
1       2       3       4       5       6       7       8       9       10      11      12      13      14      15      16
17      18      19      20      21      22      23      24      25      26      27      28      29      30      31      32
33      34      35      36      37      38      39      40      41      42      43      44      45      46      47      48
49      50      51      52      53      54      55      56      57      58      59      60      61      62      63      64
65      66      67      68      69      70      71      72      73      74      75      76      77      78      79      80
81      82      83      84      85      86      87      88      89      90      91      92      93      94      95      96
97      98      99      100

4.5 until 循环

  • 再来看看 until 循环,和 while 循环相反,until 循环时只要条件判断式不成立则进行循环,并执行循环程序。一旦循环条件成立,则终止循环。语法如下:
until [ 条件判断式 ]
do
程序
done
  • 写从 1 加到 100 这个例子,注意和 while 循环的区别
[dayuanshuai@idys day01_sh] cat until_while.sh 
# !/bin/bash

function until_perform(){

i=0
until [ $i -gt 100 ]
do
let s=s+i
let i=i+1
done
echo $s
return $s
}

function print_num(){

s=`until_perform`

echo "the num is: $s"

}

print_num

4.6 函数

  • 函数定义格式
function 函数名 () {
程序
}
  • 写一个程序,让用户自定义将数字从0累加到多少
[dayuanshuai@idys day01_sh] cat functionv1.sh 
# !/bin/bash

function add_num(){

for((i=0;i<=$1;i++))
do
  let s=s+i
done

echo $s
}

function user_input(){

read -p "please input num to decide add to " num

if echo $num | grep -E "^[[:digit:]]*$" >/dev/null 2>&1;then
    result=`add_num $num`
    echo "the end of result is $result"
else
    echo "your input is error, please input again, thank you"
fi

}

user_input

4.7 特殊流程控制语句

  1. exit 语句
  • 系统是有 exit 命令的,用于退出当前用户的登录状态。可是在 Shell 脚本中,exit 语句是用来退出当前脚本的。也就是说,在 Shell 脚本中,只要碰到了 exit 语句,后续的程序就不再执行,而直接退出脚本。exit 的语法如下:
exit [返回值]
  • 如果 exit 命令之后定义了返回值,那么这个脚本执行之后的返回值就是我们自己定义的返回值。 可以通过查询$?这个变量,来查看返回值。如果 exit 之后没有定义返回值,脚本执行之后的返回值是执行 exit 语句之前,最后执行的一条命令的返回值。写一个 exit 的例子:
[dayuanshuai@idys day01_sh] cat exit_num.sh 
# !/bin/bash

function test_num(){
read -p "please input num" -t 60 num
num_second=`echo "$num" | grep -o '[^[:digit:],[:space:]]' | sed ':t;N;s/\n//g; b t;'`

[ -n "$num_second" ] && echo "your inout is error, please inpuit again" && exit 18

echo "your input num is $num"
}

test_num

  • 现在执行这个程序
[dayuanshuai@idys day01_sh] bash exit_num.sh 
please input numsdfs2342
your inout is error, please inpuit again
[dayuanshuai@idys day01_sh] echo $?
18
[dayuanshuai@idys day01_sh] bash exit_num.sh 
please input num123
your input num is 123
[dayuanshuai@idys day01_sh] echo $?
0

  1. break 语句
  • 再来看看特殊流程控制语句 break 的作用,当程序执行到 break 语句时,会结束整个当前循环。 而 continue 语句也是结束循环的语句,不过 continue 语句单次当前循环,而下次循环会继续。

  • break语句演示
[dayuanshuai@idys day01_sh] cat break_type.sh 
# !/bin/bash

function break_num(){
for i in `seq 1 100`;do
  if [ $i -eq 4 ];then
  echo "your num is into 4,we will auto exit"
  break 
  fi
  echo "$i"
done

}

break_num
  • 语句执行
[dayuanshuai@idys day01_sh] bash break_type.sh 
1
2
3
your num is into 4,we will auto exit

  1. continue 语句
  • 再来看看 continue 语句,continue 也是结束流程控制的语句。如果在循环中,continue 语句只会结束单次当前循环
  • continue语句演示
[dayuanshuai@idys day01_sh] cat continue_type.sh 
# !/bin/bash

function contine_perform(){
for((i=0;i<10;i++));do
  if [ $i -eq 6 ];then
  echo "**************"
  continue
  fi
echo "$i"
done
}

contine_perform
  • continue语句演示
[dayuanshuai@idys day01_sh] bash continue_type.sh 
0
1
2
3
4
5
**************
7
8
9

continue 只会退出单次循环,所以并不影响后续的循环



写在最后的话:

  • 无论每个知识点的难易程度如何,我都会尽力将它描绘得足够细致
  • 欢迎关注我的CSDN博客,IDYS’BLOG
  • 持续更新内容
    linux基础 | 数据通信(路由交换,WLAN) | Python基础 | 云计算
  • 如果你有什么疑问,或者是难题。欢迎评论或者私信我。你若留言,我必回复!
  • 虽然我现在还很渺小,但我会做好每一篇内容。谢谢关注!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值