shell脚本
一、shell脚本常用的命令
1. cat,head,tail命令
1
2
3求/etc/passwd文件第20行内容 [root@manager test1]# cat -n /etc/passwd | head -20 | tail -1
2. rev,tac命令
rev左右颠倒
tac上下颠倒
3. find命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23常用选项 -name -type -user -nouser -group -nogroup -mtime -size 可以使用 -o 或者 -a 连接多个条件 可以使用-exec或者-ok来执行shell命令 find /etc/ -name hosts -exec cp {} /tmp/ ; 如: find /var/logs -type f -mtime +7 -exec rm {} ; xargs 在使用f i n d命令的- e x e c选项处理匹配到的文件时, f i n d命令将所有匹配到的文件一起传递 给e x e c执行。不幸的是,有些系统对能够传递给 e x e c的命令长度有限制,这样在 f i n d命令运行 几分钟之后,就会出现溢出错误。错误信息通常是“参数列太长”或“参数列溢出”。 如: [root@manager home]# find / -name "core" -exec file {} ; [root@manager home]# find / -name "core" |xargs file
4. 计划任务crond和crondtab
1
2
3
4
5
6
7crontab -e #编辑 */10 * * * * 脚本|命令 -l #查看 -r #删除
5. &命令
当在前台运行某个作业时,终端被该作业占据;而在后台运行作业时,它不会占据终端。
xclock -update 1 & 后台运行
6. nohup命令
如果你正在运行一个进程,而且你觉得在退出帐户时该进程还不会结束,那么可以使用 n o h u p命令。该命令可以在你退出帐户之后继续运行相应的进程。 N o h u p就是不挂起的意思( n o hang up)。
该命令的一般形式为: nohup command &
nohup xclock -update 1 &
7. shell的通配符
1
2
3
4
5
6* ? [...]和[!...] [a-z] [0-9] [!a12d] {..}
8. echo命令
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-e 使转义符生效 如: 解释t n含义 -n 不换行输出 字颜色:30—–37 echo -e “033[30m 黑色字 033[0m” echo -e “033[31m 红色字 033[0m” echo -e “033[32m 绿色字 033[0m” echo -e “033[33m 黄色字 033[0m” echo -e “033[34m 蓝色字 033[0m” echo -e “033[35m 紫色字 033[0m” echo -e “033[36m 天蓝字 033[0m” echo -e “033[37m 白色字 033[0m” 字背景颜色范围:40—–47 echo -e “033[40;37m 黑底白字 033[0m” echo -e “033[41;37m 红底白字 033[0m” echo -e “033[42;37m 绿底白字 033[0m” echo -e “033[43;37m 黄底白字 033[0m” echo -e “033[44;37m 蓝底白字 033[0m” echo -e “033[45;37m 紫底白字 033[0m” echo -e “033[46;37m 天蓝底白字 033[0m” echo -e “033[47;30m 白底黑字 033[0m” 改变提示符文件的颜色 [root@manager home]# echo -e "33[40;32m" 报警声音 [root@manager home]# echo -e "07 the bell ring"
9. printf命令
1
2
3
4
5
6
7
8
9
10[root@manager home]# printf aa aa[root@manager home]# printf "aan" aa 格式化输出 [root@manager home]# printf "%s,%s,%dn" hello world 123 hello,world,123 %s 字符串 %d十进制整数
10. read命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18可以使用r e a d语句从键盘或文件的某一行文本中读入信息,并将其赋给一个变量。如果只指定了一个变量,那么 r e a d将会把所有的输入赋给该变量,直至遇到第一个文件结束符或回 车。 如: 赋值 [root@manager home]# read name zhangsan [root@manager home]# echo $name zhangsan 赋多值 [root@manager home]# read firstname lastname huibin zhang [root@manager home]# echo $firstname $lastname huibin zhang 交互式: [root@manager home]# read -p "input a num: " var input a num: 123 [root@manager home]# echo $var 123
11. |管道命令
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管道(Pipe)实际是用于进程间通信的一段共享内存. 创建管道的进程称为管道服务器,连接到一个管道的进程为管道客户机 管道命令的两个作用: 1.管道两边产生两个子进程 2.前一个进程的标准输出和后一个进程的标准输入 注意以下情况不能赋值 echo 123 | read aa echo $aa ps -f | cat UID PID PPID C STIME TTY TIME CMD root 14412 14405 0 04:56 pts/3 00:00:00 -bash root 15485 14412 0 05:53 pts/3 00:00:00 ps -f root 15486 14412 0 05:53 pts/3 00:00:00 cat 3个进程没有任何父子进程关系 如图: bash ps -f | cat 1000 2000 3000 echo 123 | read a bash |______ps -f > |______cat < bash |______echo 123 > |______read a <
12. 重定向(文件描述符)
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文件描述符:进程连接到文件时,获得的一个标记.当进程操作文件时,首先 打开文件 获得打开文件的一个状态,给它一个标记 成为文件描述符 0标准输入 1标准输出 2标准错误输出 > >> 定向符(重定向) >覆盖 >>追加 1> 标准正确输出,文件存在则覆盖,不存在则创建 1>> 标准正确输出,文件存在则追加,不存在则创建 2> 标准错误输出,文件存在则覆盖,不存在则创建 2>> 标准错误输出,文件存在则追加,不存在则创建 &> 标准正确和标准错误输出,文件存在则覆盖,不存在则创建 cat < /dev/sda > /dev/null 测试改变文件描述符 ls >cleanup.out 2>&1 在上面的例子中,我们将 ls命令的输出重定向到 cleanup.out文件中,而且其错误也 被重定向到相同的文件中。 2>&1 标准错误输出定向到标准正确输出 < 输入重定向 后边跟的是文件 > >> << here document 后边跟的是一个文本 如下 cat > x.txt << EOF > sdfsadlkf > asdfsadhf > asfdhkasfd > EOF ------------直到遇到EOF结束 [root@manager tmp]# fdisk /dev/sda <<EOF > n > > +200M > w > EOF <<<here string 后边跟字符串 直接交给文本 如: cat >x.txt <<<asdadad cat x.txt
13. tee命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15t e e命令作用可以用字母 T来形象地表示。它把输出的一个副本输送到标准输出,另一个 副本拷贝到相应的文件中。如果希望在看到输出的同时,也将其存入一个文件, 这种情况可以使用tee命令 如: [root@manager home]# who | tee who.out root pts/1 2016-09-18 07:50 (192.168.10.102) [root@manager home]# cat who.out root pts/1 2016-09-18 07:50 (192.168.10.102) [root@manager home]# find /etc -name hosts | tee aa.txt /etc/hosts [root@manager home]# cat aa.txt /etc/hosts
14. sort命令
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[root@manager tmp]# cat aa.txt 2 4 3 21 90 78 45 23 2 3 5 1 [root@manager tmp]# sort aa.txt 1 2 2 21 23 3 3 4 45 5 78 90 [root@manager tmp]# sort -n aa.txt 1 2 2 3 3 4 5 21 23 45 78 90 [root@manager tmp]# sort -n -r aa.txt 按完整数字排序 降序 90 78 45 23 21 5 4 3 3 2 2 1 [root@manager tmp]# sort -u aa.txt 去掉重复值 1 2 21 23 3 4 45 5 78 90 [root@manager tmp]# sort -t: -k3nr /etc/passwd
15. uniq命令(默认去掉连续的重复值)
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[root@manager tmp]# cat aa.txt 2 4 4 3 3 21 90 78 45 23 2 3 5 1 [root@manager tmp]# uniq aa.txt 连续的去掉 2 4 3 21 90 78 45 23 2 3 5 1 [root@manager tmp]# uniq -u aa.txt 显示未重复值 2 21 90 78 45 23 2 3 5 1 [root@manager tmp]# sort -n aa.txt | uniq -u 排序去重 1 5 21 23 45 78 90 [root@manager tmp]# sort -n aa.txt | uniq -d 显示重复行 2 3 4 [root@manager tmp]# sort -n aa.txt | uniq -d -c 统计重复次数 2 2 3 3 2 4
16. grep命令
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--color -i 忽略大小写 -A 后几行 -B 前几行 -C 前后几行 -r 递归目录 -l 只显示匹配文件名 -x 完全一样 -n 显示行号 [root@manager tmp]# grep root /etc/passwd root:x:0:0:root:/root:/bin/bash operator:x:11:0:operator:/root:/sbin/nologin [root@manager tmp]# grep ^root /etc/passwd root:x:0:0:root:/root:/bin/bash [root@manager tmp]# grep halt$ /etc/passwd halt:x:7:0:halt:/sbin:/sbin/halt [root@manager tmp]# grep -A 2 root /etc/passwd [root@manager tmp]# grep -B 2 root /etc/passwd [root@manager tmp]# grep -C 2 root /etc/passwd [root@manager tmp]# grep -c root /etc/passwd 统计行数 2 [root@manager tmp]# grep -n root /etc/passwd 1:root:x:0:0:root:/root:/bin/bash 11:operator:x:11:0:operator:/root:/sbin/nologin [root@manager tmp]# grep -r root /etc/ 过滤所有文件 [root@manager tmp]# grep -rl root /etc/ 列出文件名 [root@manager farm]# grep -rl 'localhost' /usr/local/apache/htdocs/farm/ [root@manager tmp]# cat aa.txt abc ABC xyz XYZ [root@manager tmp]# grep abc aa.txt abc [root@manager tmp]# grep -i abc aa.txt abc ABC [root@manager tmp]# grep -ix abc aa.txt ABC [root@manager tmp]# grep -i ^abc$ aa.txt ABC
17. cut命令(截取)
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[root@manager tmp]# cat aa.txt 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 [root@manager tmp]# cut -c 1 aa.txt r b d a l [root@manager tmp]# cut -c 1,3,5 aa.txt ro: bnx deo amx l:: [root@manager tmp]# cut -c 1-5 aa.txt root: bin:x daemo adm:x lp:x: [root@manager tmp]# cut -d: -f 1 aa.txt root bin daemon adm lp [root@manager tmp]# cut -d: -f 1,3,5 aa.txt root:0:root bin:1:bin daemon:2:daemon adm:3:adm lp:4:lp [root@manager tmp]# cut -d: -f 1-5 aa.txt root:x:0:0:root bin:x:1:1:bin daemon:x:2:2:daemon adm:x:3:4:adm lp:x:4:7:lp [root@manager tmp]# cat cc.txt aa cc kk hh [root@manager tmp]# cut -d' ' -f 1 cc.txt aa kk
18. tr命令(替换)
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• 大小写转换。 • 去除控制字符。 • 删除空行。 [a-z] a-z内的字符组成的字符串。 [A-Z] A-Z内的字符组成的字符串。 [0-9] 数字串 - s选项去掉重复字符 [root@manager etc]# echo "hellooooooo worlddddddd" | tr -s "[a-z]" helo world [root@manager tmp]# cat tt.txt hellooooooooooooo worldddddddddddddddddddd [root@manager tmp]# cat tt.txt | tr -s '[a-z]' helo world [root@manager tmp]# cat tt.txt | tr -s '[a-k][m-z]' hello world 删除空行 [root@manager home]# tr -s "[n]" < aa.txt 1.robin 19 2.zorro 30 3.tom 35 大小写转换 [root@manager home]# tr "[a-z]" "[A-Z]" < cc.txt 1.ROBIN MAN 2.ZORRO MAN 3.TOM MAN 如果需要删除文件中^M,并代之以换行。使用命令: tr -s "[r]" "[n]" < file.txt
19. wc命令
1
2
3
4
5
6
7
8
9
10-l -w -c [root@manager ~]# wc -l /etc/passwd 49 /etc/passwd [root@manager tmp]# wc -w kk.txt 3 kk.txt [root@manager tmp]# wc -c kk.txt 6 kk.txt
20. eval,date,logger,bc命令
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
93eval命令 [root@manager home]# aa="cat cc.txt" [root@manager home]# echo $aa cat cc.txt [root@manager home]# eval $aa 1.robin man 2.zorro man 3.tom man date命令 [root@manager tmp]# date 2016年 09月 15日 星期四 01:20:48 CST [root@manager tmp]# date +%F 2016-09-15 [root@manager tmp]# date 月日时份年.秒 [root@manager tmp]# date -s "20161015 10:10:10" 2016年 10月 15日 星期六 10:10:10 CST [root@manager tmp]# date +%Y-%m-%d-%H-%M-%S 2016-09-20-13-58-09 logger命令 [root@manager tmp]# logger "hello i am robin" 自定日志保存位置 [root@manager tmp]# vim /etc/rsyslog.conf local5.* /tmp/test.log [root@manager tmp]# service rsyslog restart [root@manager tmp]# logger -p local5.err -t test -f /tmp/test.log hhhhhhh -p日志级别 -t 标记 -f 日志位置 bc命令(支持小数运算) 整数 [root@manager ~]# bc bc 1.06.95 Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc. This is free software with ABSOLUTELY NO WARRANTY. For details type `warranty'. 1+2 3 3-1 2 2*2 4 2/2 1 5%2 1 5^2 25 小数 [root@manager ~]# bc bc 1.06.95 Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc. This is free software with ABSOLUTELY NO WARRANTY. For details type `warranty'. scale=3 7/3 2.333 进制转换 [root@manager ~]# bc bc 1.06.95 Copyright 1991-1994, 1997, 1998, 2000, 2004, 2006 Free Software Foundation, Inc. This is free software with ABSOLUTELY NO WARRANTY. For details type `warranty'. ibase=10;obase=2 10 1010 2 10 ibase=8;obase=10 9 11 ibase=10;obase=16 11 B 非交互式 [root@manager ~]# echo "1+2" | bc 3 [root@manager ~]# echo "scale=3;3/2" | bc 1.500 [root@manager ~]# echo "ibase=10;obase=2;7" | bc 111 [root@manager tmp]# echo "obase=8;19" | bc 23 [root@manager tmp]# echo "obase=2;F" | bc 1111 [root@manager tmp]# echo "2^10" | bc 1024 计算平方根 [root@manager ~]# echo "sqrt(100)" | bc 10
21. 其他
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
84basename命令 [root@manager ~]# basename /var/log/messages messages [root@manager ~]# basename /var/log/ log split命令(分割文件) [root@manager home]# cp /etc/passwd ./ [root@manager home]# split -l 2 passwd [root@manager home]# ls passwd xaa xab xac xad xae xaf xag xah xai xaj [root@manager home]# cat xaa root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin [root@manager tmp]# cat passwd | split -l 10 [root@manager tmp]# ls passwd xaa xab xac xad xae [root@manager tmp]# split -b 1 aa.txt [root@manager tmp]# ls aa.txt xaa xab xac xad xae xaf join命令 有匹配域 [root@manager home]# cat aa.txt 1.robin 19 2.zorro 30 3.tom 35 [root@manager home]# cat cc.txt 1.robin man 2.zorro man 3.tom man [root@manager home]# join aa.txt cc.txt 1.robin 19 man 2.zorro 30 man 3.tom 35 man 如果一个文件与另一个文件没有匹配域时怎么办?这时 j o i n不可以没有参数选项,经常指 定两个文件的- a选项。下面的例子显示匹配及不匹配域。 [root@manager home]# join -a1 -a2 aa.txt cc.txt 1.robin 19 man 2.zorro 30 man 3.tom 35 man 4.jerry man [root@manager home]# join aa.txt cc.txt 1.robin 19 man 2.zorro 30 man 3.tom 35 man paste用法 paste将按行将不同文件行信息放在一行。缺省情况下, p a s t e连接时,用空格或t a b键分隔 新行中不同文本,除非指定- d选项,它将成为域分隔符。 [root@manager home]# paste aa.txt cc.txt 1.robin 19 1.robin man 2.zorro 30 2.zorro man 3.tom 35 3.tom man 4.jerry man paste命令还有一个很有用的选项( -)。意即对每一个( -),从标准输入中读一次数据。 使用空格作域分隔符,以一个4列格式显示目录列表。方法如下: [root@manager etc]# ls | paste -d" " - - - - - - ||逻辑或 前边命令失败执行后边命令 &&逻辑与 前边命令成功运行后边命令 pwd && echo ok adfa && echo ok pwd || echo ok adfa || echo ok
22. 练习
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
101
102
103
104
105
106
107
1081.统计当前系统中有多少个用户可以登录 [root@manager ~]# grep "/bin/bash$" /etc/passwd | wc -l 14 [root@manager ~]# grep -c "/bin/bash$" /etc/passwd 14 [root@manager ~]# cut -d: -f 7 /etc/passwd | grep bash | uniq -c 14 /bin/bash 2.取ip地址? [root@manager ~]# ifconfig eth2 | head -2 | tail -1 | cut -d':' -f 2 | cut -d' ' -f 1 [root@manager ~]# ifconfig eth2 | grep Bcast | cut -d':' -f 2 | cut -d' ' -f 1 172.16.20.1 [root@manager ~]# ifconfig | grep Bcast | cut -d':' -f 2 | cut -d' ' -f 1 172.16.20.1 172.16.20.201 3. [root@manager ~]# stat install.log File: "install.log" Size: 8003 Blocks: 16 IO Block: 4096 普通文件 Device: 802h/2050d Inode: 130307 Links: 1 Access: (0644/-rw-r--r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2016-09-09 06:29:21.250999892 +0800 Modify: 2016-09-09 06:30:57.320999775 +0800 Change: 2016-09-09 06:30:59.526999773 +0800 取时间 06:29:21 06:30:57 06:30:59 [root@manager ~]# stat /root/install.log | tail -3 | cut -d" " -f3 | cut -d'.' -f 1 18:02:07 09:54:49 09:54:49 [root@manager ~]# stat /root/install.log | tail -3 | cut -d" " -f1,3 | cut -d'.' -f 1 Access: 18:02:07 Modify: 09:54:49 Change: 09:54:49 4.将ip地址192.168.10.100转换成点分二进制 [root@manager ~]# echo "obase=2;192" | bc 11000000 [root@manager ~]# echo "obase=2;168" | bc 10101000 [root@manager ~]# echo "obase=2;10" | bc 1010 [root@manager ~]# echo "obase=2;100" | bc 1100100 5.将passwd文件按uid排序?按gid排序? [root@manager ~]# sort -t: -k3n /etc/passwd [root@manager ~]# sort -t: -k4n /etc/passwd 作业: 写一个 一键配置yum库脚本 [root@manager test1]# cat yum.sh #!/bin/bash #configure yum scripts #mount cdrom umount /yum mount /dev/cdrom /yum #configure yum rm -rf /etc/yum.repos.d/* touch /etc/yum.repos.d/yum.repo cat > /etc/yum.repos.d/yum.repo <<EOF [CentOS6.6] name=server baseurl=file:///yum gpgcheck=0 enabled=1 EOF #test yum yum clean all yum makecache [root@mycat ~]# mount /dev/cdrom /mnt/ [root@mycat ~]# cd /etc/yum.repos.d/ [root@mycat yum.repos.d]# mkdir old [root@mycat yum.repos.d]# mv * old [root@mycat yum.repos.d]# touch local.repo [root@mycat yum.repos.d]# cat > local.repo <<EOF > [local] > name=local > baseurl=file:///mnt > gpgcheck=0 > enabled=1 > EOF [root@mycat yum.repos.d]# yum clean all [root@mycat yum.repos.d]# yum makecache #!/bin/bash mount /dev/cdrom /mnt/ cd /etc/yum.repos.d/ mkdir old mv * old touch local.repo cat > local.repo <<EOF [local] name=local baseurl=file:///mnt gpgcheck=0 enabled=1 EOF yum clean all yum makecache
二、shell脚本基本支持及变量
1. 基础知识
1.shell脚本的格式注意事项
2.shell脚本文件的扩展名
3.shell脚本执行顺序以及产生后果(如出现错误)
a /tmp/test
rm –rf
a
/
∗
4.
用
户
身
份
的
不
同
执
行
脚
本
的
区
别
5.
s
h
e
l
l
种
类
的
介
绍
(
n
o
l
o
g
i
n
和
锁
定
区
别
)
及
用
户
切
换
切
换
s
h
e
l
l
方
式
(
b
a
s
h
c
h
s
h
−
l
)
6.
历
史
命
令
的
介
绍
h
i
s
t
o
r
y
!
!
!
100
!
s
e
r
!
a/* 4.用户身份的不同执行脚本的区别 5.shell种类的介绍(nologin和锁定区别)及用户切换切换shell方式(bash chsh -l) 6.历史命令的介绍history !! !100 !ser !
a/∗4.用户身份的不同执行脚本的区别5.shell种类的介绍(nologin和锁定区别)及用户切换切换shell方式(bashchsh−l)6.历史命令的介绍history!!!100!ser! alt+.
7.Shell退出时执行的命令.bash_logout
8.别名的介绍alias(以及命令的回顾)
2. 变量
1.环境变量
环境变量是一个具有特定名字的对象,它包含了一个或者多个应用程序所将使用到的信息。例如path,当要求系统运行一个程序而没有告诉它程序所在的完整路径时,系统除了在当前目录下面寻找此程序外,还应到path中指定的路径去找。用户通过设置环境变量,来更好的运行进程
环境变量:系统在启动过程中预先指定好的一系列的变量.比如当前用户是谁 当前shell是什么 当前用户的家目录在什么位置等等
2.预定义变量
预定义变量:系统预定义好的 和进程名称 进程编号 进程参数 进程返回值相关
3.位置变量:和命令行参数相关
4.自定义变量(用户自己定义的变量)
第一类 环境变量
环境变量 echo
env 查看所有环境变量
echo $变量名 输出变量
PATH
USER
HOME
HOSTNAME
PWD
UID
PS1
LANG=zh_CN.UTF8 (setup,yum groupinstall.系统时间)
set 查看所有变量(包括环境变量和非环境变量)
非环境变量:为用户定义的变量
export x=100 环境变量 可以被子进程所调用
y=200 非环境变量 不能被子进程所调用
环境变量和非境变量永久生效,写入配置文件
每个用户家目录下的环境变量配置文件:
.bash_history 保存用户执行过来历史命令,当用户退出时保存
.bash_logout 保存用户退出时执行的命令
.bash_profile 保存用户定义环境和启动项目,用户执行命令时的搜索路径
.bashrc 保存用户别名和函数
.bash_profile 登录级别环境配置文件
.bashrc shell级别的环境配置文件
/etc/bashrc 全局shell级别环境配置文件
/etc/profile 全局登录级别环境配置文件
登录时加载的配置文件顺序
/etc/profile
.bash_profile
.bashrc
/etc/bashrc
su - robin 和 su robin 切换帐号的区别
su - robin 登录级别切换
su robin shell级别切换
1
2
3
4
5
6
7
8
9
10
11
12
13练习: 1.当robin用户退出时,清除自己所有的历史命令 [root@manager robin]# vim /home/robin/.bash_logout rm -rf /home/robin/.bash_history history -c 2.设置别名myip 要求:所有用户可以调用这个别名 [root@manager robin]# vim /etc/bashrc alias myip="ifconfig eth2 | grep Bcast | cut -d':' -f 2 | cut -d' ' -f 1" 3.当一个用户登录时将这个用户登录的用户名,时间写入到/tmp/login.txt文件 [root@manager robin]# vim /etc/profile echo "$USER" 'login' `date` >> /tmp/login.txt
第二类 预定义变量$0 KaTeX parse error: Can't use function '$' in math mode at position 2: $̲# $? $* $0 进程名(… 当前进程号(/var/run 模拟系统结束进程)
$# 位置参数的数量
$* 表示在命令行中实际给出的所有实参字符串
$? 命令执行后的返回状态.0为执行正确,非0为执行错误
$! 后台运行的最后一个进程的进程号
第三类 位置变量
位置变量: 和命令行参数相关 (命令后跟的参数$1-$9)
第四类自定义变量
自定义变量:当用户变量不够用时,自定义的变量
1
2
3
4
5
6
7
8
9
10
11
12
13
14如下测试脚本 #!/bin/bash cd /tmp touch a.txt ls –ld /tmp du –sh /tmp 改为 #!/bin/bash $DIR=/tmp cd $DIR touch a.txt ls –ld $DIR du –sh $DIR
练习:
计算器 四则运算
./脚本 1 + 2
3
再进一步完善脚本read 命令的使用
算式运算符:
1
2
3
4
5
6
7
8
9
10
11
12+、-、*、/、() #$()优先执行 $(())运算 1.$((5+3)) 2.$[ 5+3 ] 3.expr操作符: +、-、*、/、%取余(取模) expr 1 + 2 4.a=1;b=2 let c=$a+$b echo $c
export作用范围
父子shell的说明,及变量的定义
如例子:
a.sh
1
2
3
4
5#!/bin/bash echo IN a.sh’ aa=123 ./b.sh
b.sh
1
2
3
4#!/bin/bash echo ‘IN b.sh’ echo $aa
运行脚本方式的介绍
./a.sh
bash a.sh
source a.sh #加载脚本
. a.sh #加载脚本,多用于调用函数库
source a.sh 和. a.sh
别名 内部命令 外部命令
1
2
3
4
5
6
7
8
9
10
11[root@manager tmp]# type ls 别名 ls is aliased to `ls --color=auto' [root@manager tmp]# type useradd 外部 产生子进程 useradd is /usr/sbin/useradd [root@manager tmp]# type cd 内部 不产生子子进程在当前环境下运行 cd is a shell builtin
别名>外部命令>内部
利用当前的shell执行后边的脚本 如果没有外部命令 则不产生子进程
如测试脚本如下
cat aa.sh
#!/bin/bash
cd /
pwd
./ aa.sh
. aa.sh
函数库定义
函数库:将常用的变量定义到一个文件里 直接加载这个文件 就不用重复定义变量了
如系统中的确定与失败
子进程定义的变量能否被父进程集成?
nologin shell 和 login shell
/etc/bashrc
/etc/profile
~/.bashrc
~/.bash_profile
read命令的使用
read命令:将脚本后边跟着的变量的值读取到脚本中
-p –t 参数的说明
如下边这个有趣的脚本:
1
2
3
4
5#!/bin/bash read -p "请输入银行卡账号: " num read -p "请输入银行卡密码: " -t 5 pass echo 账号$num 密码$pass >> /tmp/haha.txt
yum install postfix
service postfix restart
1
2
3
4
5
6
7
8
9
10
11
12#!/bin/bash read -p "输入帐号: " account stty -echo #去掉终端输出 read -p "输入密码: " -t 5 pass stty echo #恢复终端输出 echo echo "帐号:$account 密码:$pass" >> /tmp/login.txt echo "帐号:$account 密码:$pass" | mail -s "auth" root@localhost
算式置换
a=10+20
a=
(
(
10
+
20
)
)
命
令
置
换
(
将
命
令
执
行
结
果
赋
给
变
量
)
a
=
‘
d
a
t
e
+
a
=
((10+20)) 命令置换(将命令执行结果赋给变量) a=`date +%m%d` a=
((10+20))命令置换(将命令执行结果赋给变量)a=‘date+a=(date +%m%d) 推荐
[root@manager test1]# file=ls
date +%F`` 报错
[root@manager test1]# file=$(ls $(date +%F))
[root@manager test1]# echo $file
2016-09-20
原因
a=ls
date +%m%d`` 该赋值失败
a=$(ls $(date +%m%d ))
通配符
通配符是shell解释的 正则表达式是命令解释的
*匹配任所有字符
?匹配一个字符
[]匹配一个范围
{}如touch abc{a,b,c}{1…3}.txt
变量的引用
echo 命令介绍
echo -n -e参数说明 “”’’说明 n t
echo $
echo ’$’
1
2
3
4
5
6
7
8
9
10
11[root@manager test1]# echo hello world;i am robin 报错 [root@manager test1]# echo "hello world;i am robin" hello world;i am robin [root@manager test1]# echo 'hello world;i am robin' hello world;i am robin [root@manager test1]# name=robin [root@manager test1]# echo 'hello world;i am $name' hello world;i am $name [root@manager test1]# echo "hello world;i am $name" hello world;i am robin
三、test命令及判断语法
1. test命令的使用
语法:test EXPRESSION 或者 [ EXPRESSION ]
字符串判断(用于看用户有没有输入指定的变量 指定用户输入目录 如没
填)
-n 字符段长度是否非零的 如果结果为真值 返回值为0 如果结果为假值
返回值非0
-z 判断是否为空 ,和-n相反
例:判断两个文件名字是否一致
mkdir /a /b
touch /a/x.txt /b/x.txt
[ “/a/x.txt”="/b/x.txt"] 可定错误不同 目录名称不同
应为
[ “
(
b
a
s
e
n
a
m
e
/
a
/
x
.
t
x
t
)
"
=
"
(basename /a/x.txt)"="
(basename/a/x.txt)"="(basename /b/x.txt)” ]
test 整数
eq 等于
ge 大于等于
gt 大于
le 小于等于
lt 小于
ne 不等于
test 文件
ef 两个文件有相同的设备编号和inode编号 (判断硬链接)
touch aa
ln aa bb
ls -i
456733 aa 456733 bb
根据文件类型判断
-d 文件存在必须是个目录
-e 有文件名存在就行不管类型
-f 文件存在而且是个标准普通文件
-h 文件存在并且是否为符号链接文件
-r 判断文件权限是否有r权限
-w 写权限
-x 执行权限
条件判断语句
if cmd;如为真值
then
fi 执行
如为假值则不执行
例
if [ -f /etc/passwd ]
then
echo ok
fi
若文件不存 则 不执行
if useradd uu3
then
id uu3
fi
添加成功则显示用户信息
if [ -f /etc/ssh/sshd_config ]
then
service sshd start
else
echo ssh is not install
fi
练习:
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
261.提示输入一个用户名字,判断该用户是否存在?存在显示其信息(uid gid 家目录 shell),不存在添加该帐号 #!/bin/bash read -p "输入用户名: " username if id $username &> /dev/null then echo "用户存在,显示信息" grep ^${username}: /etc/passwd | cut -d':' -f 1,3,4,6,7 else echo "用户$username不存在,添加用户" useradd $username fi 2.提示输入文件路径及文件名,判断该文件是否存在,存在显示其详细信息,不存在创建该文件 [root@manager test1]# cat file.sh #!/bin/bash read -p "输入完整文件名: " file if [ -f $file ] then echo "文件存在,显示文件信息" ls -l $file else echo "文件不存在,创建文件" touch $file fi
if语句的嵌套
if cmd
then
………
else
if cmd
then
……….
else
…………
fi
fi
提示输入文件路径及文件名,判断改文件是否存在,
判断改文件是否size为0
如果不为0 显示其详细信息,
如果为0 删除改文件 重新创建并写入内容hello world
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18#!/bin/bash read -p "输入文件信息:" filename if [ -f $filename ] then echo "${filename}存在" if [ -s $filename ] #判断大小是否大于0,大于0时返>回0 then ls -l $filename else rm -f $filename touch $filename echo "hello world" > $filename fi else echo "${filename}不存在" fi
if语句的完整写法
if cmd1
then
run cmd1-1
run cmd1-2
elif cmd2
then
run cmd2-1
run cmd2-2
elif cmd3
then
run cmd3-1
run cmd3-2
else
then
run cmd4-1
run cmd4-2
fi
1
2
3
4
5
6
7
8
9
10
11100数字内猜数字游戏 #/bin/bash guess=80 read -p "please insert yao number(range 1-100): " num if [ $num -eq $guess ] then echo "you are win!!!!" else echo "you are lose!!!!" fi
如果是猜随机数怎么办?($RANDOM).
正常情况应该为产生一个随机数,猜数人员有5次机会.这就需要用到循环语句
那么循环语句的结构式怎样的呢?带着上边的问题我们先学习一下循环语句
循环语句主要有两个循环语句for和while
2.练习和作业
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
1411.判断tmp下是否存在普通文件aa.txt,文件存在则输出文件详细信息,文件不存在则创建文件 #!/bin/bash file=/tmp/aa.txt if [ -f $file ] then ls -l $file else touch $file fi 2.写脚本判断脚本后边的变量个数是否超过2个 不足提示变量不足,超过提示超过 #!/bin/bash sum=$# if [ ${sum} -gt 2 ] then echo "变量超过" elif [ $sum -lt 2 ] then echo "变量不足" fi 3.提示用户输入一个变量值 判断输入的值是否为空 #!/bin/bash read -p "输入一个变量值:" num if [ -n "$num" ] then echo "不为空" else echo "为空" fi 4.从系统中搜索文件man_db.config是否存在,判断该文件和/root/install.log是否为硬链接 #!/bin/bash file=`find / -name man_db.conf` if [ $file -ef /root/install.log ] then echo "yes" else echo "no" fi 5.从系统搜索光盘镜像文件,如果有挂载使用 否则提示下载 #!/bin/bash if [ -L /dev/cdrom ] then echo "存在" mount /dev/cdrom /mnt else echo "不存在,请前往下载!" fi 6.写一个文本文件/tmp/user.txt 内容为 帐号 密码 写一个交互式脚本,让用户输入帐号 密码,判断用户输入帐号密码是否正确,如果正确提示登录成功 touch /tmp/user.txt echo "zhangsan" > /tmp/user.txt echo "123456" >> /tmp/user.txt #!/bin/bash user=`head -1 /tmp/user.txt` pass=`tail -1 /tmp/user.txt` read -p "input username:" account read -p "input password:" password if [ $user == $account -a $pass == $password ] then echo "登陆成功" else echo "失败" fi 7.写一个判断vsftpd是否正在运行的脚本 #!/bin/bash systemctl status vsftpd ftp=$? if [ $ftp -eq 0 ] then echo "有ftp进程" else echo "没有ftp进程" fi 8.写一个判断内存使用是否大于50%的脚本 #!/bin/bash use=`free | head -2 | tail -1 | cut -d' ' -f16` #awk命令更好 free=`free | head -2 | tail -1 | cut -d' ' -f23` if [ $use -gt $free ] then echo "内存使用大于50%" else echo "no" fi 9.写一个检查系统中登录用户超过5个的脚本 uptime 或者 who #!/bin/bash usernum=`who | wc -l` if [ $usernum -gt 5 ] then echo "over" else echo "no over" fi 10.完善你写过的yum库脚本 11.判断nmap命令是否存在 如果不存在则安装对应的软件包 #!/bin/bash rpm -q nmap nmap=$? if [ $nmap -eq 0 ] then echo "nmap命令存在" else echo "nmap命令不存在" yum -y install nmap fi 12.查看光盘上有哪些软件没有安装,将没有安装的软件包,安装到系统中 * 13.如何判断一个目录为空目录 #!/bin/bash read -p "input a dir:" dir num=`ls -A $dir` if [ -z "$num" ] then echo "null" else echo "no null" fi 查看咱们的网络内有多少ip地址是活跃的,并且那些ip的ssh服务是开启的? 作业: 1.判断当前用户是否为root 如果为root用户启动ssh服务 如果非root 切换用户提示用户启动服务 #!/bin/bash if [ $USER = "root" ] then echo "yes" systemctl start sshd else echo "please cut user,use sshd" fi 2.每隔3秒调用自己一次 3.分析下边脚本 a.sh #!/bin/bash echo $$ ./a.sh | ./a.sh & 4.判断自己是否为重复运行脚本,如果为重复运行的脚本则自动退出(同一 时间该脚本只有一个实例运行)
四、循环语法
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152首先学习一下for语句 如下脚本: #!/bin/bash for i in 1 3 5 7 do echo $i echo ok done 我们还可以将for循环读取的语句写到一个文件里如a.txt #!/bin/bash for I in `cat a.txt` do echo $i echo ok done 添加100个用户 #!/bin/bash for i in {1..100} do useradd zhang"$i" done time 命令的使用 real墙上时间,也就是实际消耗时间多少 user用户态消耗的时间. sys 系统底层消耗的时间(操作硬盘) 计算1-100的累加和(注意初始化值) #!/bin/bash sum=0 for i in {1..100} do let sum=$i+$sum done echo $sum 计算1-100奇数的累加和 偶数呢? #!/bin/bash sum1=0 sum2=0 for i in {1..100} do if [ $(($i%2)) -eq 1 ] then let sum1=$i+$sum1 else sum2=$(($i+$sum2)) fi done echo "偶数和:$sum2" echo "奇数和:$sum1" 更好的方式: seq 1 2 100 产生1-100个数字 步长为2 脚本就可以变得更简单了 for循环的另一种写法 模拟c语言的写法 for ((i=0;i<10;i++)) do echo $i done i+=2 i=i+2 i-=2 i=i-2 i*=2 i=i*2 i/=2 i=1/2 数值运算时这种写法更简单 如果文件处理for in的语法更容易写 好了 我们开始完成上边遗留的问题 猜数字给5次机会 #!/bin/bash number=$(($RANDOM%100+1)) for i in {1..5} do read -p "输入数字[1~100]:" guess if [ $guess -eq $number ] then echo "you are win" elif [ $guess -gt $number ] then echo "you are big" else echo "you are small" fi done 又遇到问题.猜对了的情况下还让猜 这时应该跳出脚本 不在继续猜 break 和continue 跳出循环 break 跳出当前循环 脚本继续执行 continue 跳出本次循环,脚本继续执行 exit 退出脚本, 但是exit可以设置脚本返回值 遇到某些条件时这一次的循环跳出continue (如再来一个小游戏:大家说数字1-100 遇到被7整除和含有的7的数就跳出) 我们再来看看其他循环如select循环 select i in ls pwd whoami do $i done while和until循环 while 后边跟命令 条件为真值时循环 until 后边跟命令 条件为假值时循环 更多用while做死循环 语法 while cmd do list done 如 true为真值 0 while true do sleep echo ok done :空指令 死循环 while true do : done 不会死机 cpu发现为死循环 降低该进程优先级 #!/bin/bash #14.sh x=0 while [ $x -lt 10 ] do echo $x x=`expr $x + 1` done #!/bin/bash #15.sh sum=0 while [ $sum -lt 10 ] do sum=`expr $sum + 1` useradd user$sum echo "123456" | passwd --stdin user$sum done until语法 until cmd do list done #!/bin/bash #16.sh x=1 until [ $x -ge 10 ] do echo $x x=`expr $x + 1` done 相当于 x=1 while [ ! $x -ge 10 ] do echo $x x=`expr $x + 1` done 当用户robin 登录系统时 提示robin登录系统,记录用户信息(名字 时间 tty)
五、case分支语法及函数
1. case语法结构
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
31case word in pattern1) list1 ;; pattern2) list2 ;; ... ... patternN) listN ;; * ) list * ;; esac 例如:超市卖水果 #!/bin/bash read –p “请输入你要查询的商品: ”var case $var in apple) echo "apple 1.4元每斤" ;; orange) echo "orage 1.5元每斤" ;; banana) echo "banana 1.6元每斤" :: esac /etc/init.d/sshd
用法:/etc/init.d/sshd {start|stop|restart|reload|condrestart|status}
服务用法的实现
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#!/bin/bash case $1 in start) echo "start" ;; stop) echo "stop" ;; restart|reload) echo "restart" ;; *) echo "Usage: $0 start|stop|restart" esca
在这个基础上我们来实现一个小服务的脚本
nc 命令可以监听段口
nc –l 9999
好了,我们可以启动一个小服务了
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#!/bin/bash case $1 in start) echo "start" nc –l 9999 ;; stop) echo "stop" pkill nc ;; restart|reload) echo "restart" pkill nc nc –l 9999 ;; *) echo "Usage: $0 start|stop|restart" esca
pidof取一个进程的pid
完善一些这个模拟服务的脚本,定义函数
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#!/bin/bash start(){ #定义start函数 if [ -f /tmp/nc.lock ] then echo "nc is runing" else echo "start" nc -l 9999 & touch /tmp/nc.lock fi } stop(){ #定义stop函数 if [ ! -f /tmp/nc.lock ] then echo "nc is not runing" else echo "stop" PID=$(pidof nc) kill -9 $PID rm -rf /tmp/nc.lock fi } case $1 in start) start #调用函数 ;; stop) stop ;; restart) stop sleep 1 start ;; *) echo "Usage:$0 start|stop|restart" esac
2.函数
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函数也可以让我们死机 如下 :(){ :|:& };: 可以看我们的系统服务启动脚本了 函数的参数 函数外的参数也能被函数调用 #!/bin/bash a=123 func(){ echo $a } func ./a.sh 变量在函数内 外边也能调用 #!/bin/bash func(){ a=123 } func echo $a 只在函数里调用 外部看不到 隔离变量 #!/bin/bash func(){ local a=123 echo "in func" echo $a } func echo "out of func" echo $a 给函数传递参数 #!/bin/bash sum(){ echo $(($1+$2)) } sum 10 20 如果命令参数传递给函数 #!/bin/bash a=$1 b=$2 sum(){ echo $(($1+$2)) } sum $a $b 执行a.sh 10 20 变量起名字别偷懒 起的有意义一些 让别人一目了然 如:argv1 argv2 #!/bin/bash #注明 $1 $2 为脚本参数 以免脚本过长不知道那个$1 $2 argv=$1 argv=$2 sum(){ # $1 $2 为函数参数 func_argv1=$1 func_argv2=$2 echo $(($func_argv1+$func_argv2)) } sum $a $b 练习脚本: 提取主机名 函数 提取ip地址 函数 (多网卡) 检查自己主机启动什么服务的 函数
3. 练习
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
1701.添加user1-user50个用户.再添加过程中.如果这50个用户中有已存在的用户则显示The user is in system!!!!!如果不存在则添加,并且添加密码 能不能让上边的脚本加快执行速度? #!/bin/bash for i in {1..50} do useradd user"$i" &> /dev/null if [ $? -ne 0 ] then echo "The user is in system!!!!!" else echo 123 | passwd --stdin user"$i" &> /dev/null fi done 2.打印一下矩阵 **** **** **** #!/bin/bash for ((i=0;i<4;i++)) do for ((j=0;j<4;j++)) do echo -n "* " done echo done 3.打印以下3角型 * ** *** **** #!/bin/bash for ((i=0;i<4;i++)) do for ((j=0;j<=i;j++)) do echo -n "* " done echo done 4.按用户输入数字打印一下三角型 如输入行数 n-i个空格 2i-1个* * *** ***** ******* #!/bin/bash for ((i=1;i<=4;i++)) do for ((m=1;m<=4-i;m++)) do echo -n " " done for ((j=1;j<=2*i-1;j++)) do echo -n "* " done echo done 掏空 #!/bin/bash for ((i=1;i<=4;i++)) do for ((m=1;m<=4-i;m++)) do echo -n " " done if [ $i -eq 1 -o $i -eq 4 ] then for ((j=1;j<=2*i-1;j++)) do echo -n "* " done echo else for ((j=1;j<=2*i-1;j++)) do if [ $j -eq 1 -o $j -eq $((2*$i-1)) ] then echo -n "* " else echo -n " " fi done echo fi done 倒三角 #!/bin/bash for ((i=4;i>=1;i--)) do for ((m=1;m<=4-i;m++)) do echo -n " " done for ((j=1;j<=2*i-1;j++)) do echo -n "* " done echo done 5. 按用户输入数字打印一下三角型 如输入4 * *** ***** ******* ***** *** * 梯形 圣诞树 6.打印9x9乘法表如下格式 1x1=1 1x2=2 2x2=4 …………………………… ………………………………….. ………………………………………. …………………………………………………….9x9=81 #!/bin/bash for ((i=1;i<=9;i++)) do for ((j=1;j<=i;j++)) do num=$(($i*$j)) echo -n "${i}x${j}=$num " done echo done 7.计算12345经过加减乘除等于15的式子 #!/bin/bash for i in + - * / do for j in {"+","-","*","/"} do for m in {"+","-","*","/"} do for n in {"+","-","*","/"} do num=$((1${i}2${j}3${m}4${n}5)) if [ $num -eq 15 ] then echo "1${i}2${j}3${m}4${n}5" fi done done done done + 8.写一个脚本监控你的/分区,当你的/分区的剩余空间小于10G时.给root管理员发一封邮件(测试时可以再某个文件里写一句话) #!/bin/bash while true do free=`df -T | grep /boot | awk {'print $5'}` if [ $free -lt 512000 ] then echo "/boot不足500M,剩余$free" echo "/boot不足500M,剩余$free" | mail -s 磁盘 root@localhost fi done 9.测试网络中有多少个ip是活跃,并且查询那些80端口开放 10.判断自己是否为重复运行脚本,如果为重复运行的脚本则自动退出(同一时间该脚本只有一个实例运行) 11.mysql的备份脚本(mysqldump + binlog日志)
六、变量替换及数组
变量替换(可以用if实现 这是另外一种方式)
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207一 ${parameter:-word} 若 parameter 为空或未设置,则用 word 代替 parameter 进行替换,parameter 的值不变 # a=1 # unset b # a=${b:-3} # echo $a # a=1 # b=2 # a=${b:-3} # echo $a # echo $b 二 ${parameter:=word} 若 parameter 为空或未设置,则 parameter 设为值 word # a=1 # unset b # a=${b:=3} # echo $a #echo $b # a=1 # b=2 # a=${b:=3} # echo $a # echo $b 三 ${parameter:+word} 若 parameter 设置了,则用 word 代替 parameter 进行替换,parameter 的值不变 # a=1 # unset b # a=${b:+3} # echo $a # echo $b # # a=1 # b=2 # a=${b:+3} # echo $a # echo $b 四 ${parameter:?message} 若 parameter 为空或未设置,则 message 作为标准错误打印出来,这可用来检查变量是否正确设置 # unset a # ${a:?unset a} -bash: a: unset a 字符串切片,替换 $ a=12345678 $ echo ${a:5} 678 $ echo ${a:3:4} 4567 $ a=123456123789 $ echo ${a#1*3} #最短匹配截取 456123789 $ echo ${a##1*3} #最长匹配截取 789 $ a=123 $ echo ${#a} #表示$var的长度 3 $ a=123456123789 $ echo ${a/1/} #第一次匹配的被替换(去掉) 23456123789 $ echo ${a//1/} #全局的匹配被替换 2345623789 $ echo ${a/1/x} x23456123789 $ echo ${a//1/x} x23456x23789 shell的数组分为普通数组和关联数组 普通数组 定义数组 [root@manager ~]# ary=(a b c) 数组取值 [root@manager ~]# echo ${ary[0]} a [root@manager ~]# echo ${ary[1]} b [root@manager ~]# echo ${ary[2]} c [root@manager ~]# echo ${ary[3]} [root@manager ~]# echo $ary a 或者设置数组的值为字符串 [root@manager ~]# ary=("robin" "zorro" "lucy") [root@manager ~]# echo ${ary[0]} robin [root@manager ~]# echo ${ary[1]} zorro [root@manager ~]# echo ${ary[2]} lucy 取数组所有值: [root@manager ~]# ary=("robin" "zorro" "lucy") [root@manager ~]# echo ${ary[@]} robin zorro lucy 或者 [root@manager ~]# echo ${ary[*]} robin zorro lucy 数组的重新赋值 [root@manager ~]# ary[0]="jerry" [root@manager ~]# echo ${ary[0]} jerry 删除数组赋值 [root@manager ~]# unset ary[0] [root@manager ~]# echo ${ary[0]} 删除数组 [root@manager ~]# unset ary [root@manager ~]# echo ${ary[@]} 统计数组成员个数 [root@manager ~]# ary=("robin" "zorro" "lucy") [root@manager ~]# echo ${#ary[@]} 3 统计数组成员字符个数 [root@manager ~]# ary=("robin" "zorro" "lucy") [root@manager ~]# echo ${#ary[1]} 5 [root@manager ~]# echo ${#ary[2]} 4 数组切片 [root@manager ~]# ary=("robin" "zorro" "lucy") [root@manager ~]# ary=("robin" "zorro" "lucy" "tom" "jerry") [root@manager ~]# echo ${ary[@]:1:2} zorro lucy [root@manager ~]# echo ${ary[@]:1:3} zorro lucy tom 数组成员切片 [root@manager ~]# echo ${ary[0]:1:2} ob [root@manager ~]# echo ${ary[0]:1:3} obi [root@manager ~]# echo ${ary[0]:1:4} obin [root@manager ~]# echo ${ary[1]:2:2} rr 遍历数组所有的值 [root@manager ~]# for i in ${ary[@]}; do echo $i; done a b c 关联数组 Bash支持关联数组,它可以使用字符串作为数组索引,有时候采用字符串索引更容易理解。 1.利用内嵌索引-值列表的方法 [root@manager ~]# declare -A ary [root@manager ~]# ary=([robin]=beijing [zorro]=shanghai) [root@manager ~]# echo ${ary[robin]} beijing [root@manager ~]# echo ${ary[zorro]} shanghai 2.使用独立的索引-值进行赋值 [root@manager ~]# ary[jack]=hebei [root@manager ~]# ary[rose]=henan [root@manager ~]# echo ${ary[jack]} hebei [root@manager ~]# echo ${ary[rose]} henan 取数组值 [root@manager ~]# echo ${ary[*]} shanghai beijing 取数组的键 [root@manager ~]# echo ${!ary[*]} zorro robin 获取所有键值对 [root@manager ~]# for key in ${!ary[@]} do echo "$key = ${ary[$key]}" done zorro = shanghai robin = beijing 练习: 排序 数字 134 223 45 98 76 243 8 6 1 47 石头剪刀布游戏 #!/bin/bash count1=0 count2=0 while true do guess=("石头" "剪刀" "布") num1=$(($RANDOM%3)) computer=${guess[$num1]} menu=" 0.石头 1.剪刀 2.布 请输入[0][1][2]:" read -p "$menu" num2 player=${guess[$num2]} declare -A win_case win_case=(["石头"]="剪刀" ["剪刀"]="布" ["布"]="石头") if [ ${win_case["$player"]} == "$computer" ] then echo "player is win" count1=$(($count1+1)) elif [ ${win_case["$computer"]} == "$player" ] then echo "computer is win" count2=$(($count2+1)) else echo "pingju" fi echo "$computer" echo "$player" done
七、ssh远程操作及终端控制
1. tput命令
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
32tput 可以操作光标,定位光标 tput sc 保存光标位置 tput rc 返回光标位置 tput cols 读取列数 tput lines 读取行数 tput cup lines cols tput civis # 光标不可见 tput cnorm # 光标可见 定位倒计时 #!/bin/bash col=`tput cols` line=`tput lines` ncol=$(($col/2)) nline=$(($line/2)) tput sc 爆炸 for i in {1..1000} do usleep $i tput cup $nline $ncol echo "$i" done tput cup $nline $ncol echo "爆炸" for i in {1..10} do usleep 100000 echo -e "a" done tput rc
2. ssh远程脚本
1
2
3
4
5
6
7
8
9expect非交互式 脚本代码如下: #!/usr/bin/expect set timeout 30 spawn ssh -l username 192.168.1.1 expect "password:" send "ispassr" = interact
-
[#!/usr/bin/expect]
这一行告诉操作系统脚本里的代码使用那一个shell来执行。这里的expect其实和linux下的bash、windows下的cmd是一类东西。
注意:这一行需要在脚本的第一行。 -
[set timeout 30]
基本上认识英文的都知道这是设置超时时间的,现在你只要记住他的计时单位是:秒 -
[spawn ssh -l username 192.168.1.1]
spawn是进入expect环境后才可以执行的expect内部命令,如果没有装expect或者直接在默认的SHELL下执行是找不到spawn命令的。所以不要用 “which spawn“之类的命令去找spawn命令。好比windows里的dir就是一个内部命令,这个命令由shell自带,你无法找到一个dir.com 或 dir.exe 的可执行文件。
它主要的功能是给ssh运行进程加个壳,用来传递交互指令。 -
[expect “password:”]
这里的expect也是expect的一个内部命令,有点晕吧,expect的shell命令和内部命令是一样的,但不是一个功能,习惯就好了。这个命令的意思是判断上次输出结果里是否包含“password:”的字符串,如果有则立即返回,否则就等待一段时间后返回,这里等待时长就是前面设置的30秒 -
[send “ispassr”]
这里就是执行交互动作,与手工输入密码的动作等效。
温馨提示: 命令字符串结尾别忘记加上 “r”,如果出现异常等待的状态可以核查一下。 -
[interact]
执行完成后保持交互状态,把控制权交给控制台,这个时候就可以手工操作了。如果没有这一句登录完成后会退出,而不是留在远程终端上。如果你只是登录过去执行一段命令就退出,可改为[expect eof]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15shell脚本嵌套expect脚本 cat ssh.sh #!/bin/bash pass=123 /usr/bin/expect <<EOF set timeout 30 spawn scp /root/install.log 192.168.1.1:/home expect "password:" send "$passr" expect eof EOF #必须顶行 添加用户natasha 密码redhat
终端控制
#!/bin/bash
gnome-terminal --geometry=34x8+0+0 -e /tmp/aa.sh
gnome-terminal --geometry=34x8+700+0 -e /tmp/aa.sh
gnome-terminal --geometry=34x8+0+700 -e /tmp/aa.sh
gnome-terminal --geometry=34x8+700+700 -e /tmp/aa.sh
八、正则表达式
1. 正则对照表
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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235find grep sed awk vim python php 正则表达式 算术表达式: 1+2 3*5 1+2*3 (1+2)*3 正则表达式在匹配的时候一定要有一定规律,否则无法匹配 如下 特定的模式: A B C … … -> a b c … … ABC ADC AEC … … ab abb abbb abbbb abbbb… … 正则表达式的匹配过程 如: grep halt /etc/passwd 那我们通过grep来学习正则吧 grep命令是linux下的行过滤工具,其参数繁多, grep -- print lines matching a pattern (将符合样式的该行列出) ◎语法: grep [options] PATTERN [FILE...] grep用以在file内文中比对相对应的部分,或是当没有指定档案时, 由标准输入中去比对。 在预设的情况下,grep会将符合样式的那一行列出。 其中egrep就等同于grep -E 常用参数 -A 匹配行的后多少行 -B 匹配行的前多少行 -C 前后行 -c 统计匹配行 -i 忽略大小写匹配 -E 扩展正则 -n 显示匹配行行号 -x 显示完全匹配的行 -v 取反 如下文件 a.txt 我要找到含有ABC ADC AEC 的行 asdfasdf ABC aasdajsd afdafjal ADC qqweqeqwe qweqe AEC adfajf grep A.C a.txt 这里的.称为元字符 元字符 . 匹配除换行符之外的任意单个字符,awk中可以匹配换行符 * 匹配任意一个(包括零个)在它前面的字符 如下 a ab ac abb abc abbc abbbbbbbbbbbc grep ab* b.txt grep ab*c b.txt grep a* b.txt .*任意一个字符出现一次到多次 asadfsadfc ac afdsdfasdfasdfasdfc aacc aaaaaa1ccccccccc2aaaaaaaaaa3ccccccccc4 grep a.*c c.txt [...] 匹配方括号中的任意一个字符,^为否定匹配, -表示字符的范围 acc a.c abc a2c a6c a7c a8c grep [6789]c a.txt grep [1-9]c a.txt grep [^1-9]c a.txt 1+2 1-2 1*2 1/2 grep ‘[+-*/]’ a.txt #必须将-放在开头或者结尾 ^和$ root aroot roota grep ^root a.txt grep root$ a.txt grep ^root$ a.txt 只包含3个字符? ^...$ 最少包3个字符? ... 匹配空行?显示行号? grep -n ^$ 多个空格的空行? grep -n "^ *$" grep "t"是不行的,应该输入一个正在的制表符,方法为先按 CTRL+V,再按 Tab 键。 转意字符 abc a,c grep a,c a.txt 扩展元字符 + 匹配前面的正则表达式的一次出现或多次出现 a ab abb abbb grep ab+ a.txt ? 前边字符出现0或1次 可能有可能没有 y yes Y Yes grep -E [Yy][es]? a.txt | 替代方案l company companies grep -E compan'[y|iess]' a.txt grep -E compan’(y|iess)’a.txt {n,m}匹配出现的n到m次数, {n}匹配出现n次。{n,}匹配至少出现n次, 大多数awk都不支持,用于POSIX egrep和POSIX awk aaaa 4 aaaaa 5 aaaaaa 6 aaaaaaa 7 grep -E a{4,5} a.txt 字符类 [Ww]hat .H[12345] 字符的范围 [a-z] [0-9] [Cc]hapter[1-9] [-+*/] [0-1][0-9][-/][0-3][0-9][-/][0-9][0-9] [root@manager test5]# grep -E "(15:[0-2][0-9]|15:4[0-5]:)" /var/log/secure 排除字符类 [^0-9] 重复出现的字符 5 10 50 100 500 1000 5000 [15]0* [15]00* 字符的跨度 * 与 {n,m} 电话号码的匹配 [0-9]{3,4}-[0-9]{7,8} 分组操作 compan(y|ies) sed和awk sed和awk用于处理文本,在linux中大量操作都涉及到文本,如系统日志,应用程序日志.批量处理时对配置文件做修改.操作文件时有些文件的语法不规范,如messages有空格分隔 :分隔 分号分隔 ,号分隔 如apache日志,分隔符不明显,而且分割时都是特殊字符,提取时我们可能只要ip 访问目标地址 访问时间 还有格式修改,sed主要处理不规范的格式改为规范. sed是一个“非交互式的”面向字符流的编辑器,awk是一种负责模式匹配的程序设计语言,它的典型示例是将数据转换成格式化的报表。 sed流媒体编辑器的使用 练习文本: John Daggett, 341 King Road, Plymouth MA Alice Ford, 22 East Broadway, Richmond VA Orville Thomas, 11345 Oak Bridge Road, Tulsa OK Terry Kalkas, 402 Lans Road, Beaver Falls PA Eric Adams, 20 Post Road, Sudbury MA Hubert Sims, 328A Brook Road, Roanoke VA Amy Wilde, 334 Bayshore Pkwy, Mountain View CA Sal Carpenter, 73 6th Street, Boston MA (名字 街道 城市 大州) dos2unix 文件转换 unix2dos 在windows和linux之间文本格式互转的工具 linux n windows nr 换行 语法 sed ‘args’ file.txt file2.txt 但是官方文档称args为命令 sed ‘cmd’file.txt file.txt 替换: sed ‘s/old/new/’ file1.txt 结果显示在屏幕上云文件不变 sed 's/MA/Massachusett/' file1.txt 格式调整 sed 's/ MA/, Massachusetts/' file1.txt 多条处理 sed 's/ MA/, Massachusetts/ ; s/ PA/, Pennsylvania/' file1.txt 或者 sed -e 's/ MA/, Massachusetts/' -e 's/ PA/, Pennsylvania/' file1.txt 脚本支持 脚本:sedsrc s/ MA/, Massachusetts/ s/ PA/, Pennsylvania/ s/ CA/, California/ s/ VA/, Virginia/ s/ OK/, Oklahoma/ sed -f sedsrc file1.txt 保存输出 sed -f sedsrc file1.txt > newfile.txt 阻止输入行自动显示 sed -n 's/MA/Massachusetts/p' file1.txt awk的简单使用 语法 awk ‘{主输入循环}’file 输出每个人的名字 awk ‘{print $1}’file #$0代表所有 第二列 默认分隔符(一个空格 多个空格 一个制表符 多个制表符) 所以,显示 awk ‘{print $2}’file 指定分隔符 awk –F, ‘{ print$1 }’file1.txt //匹配功能如 匹配包含MA的行 awk ‘/MA/’file1.txt 还想要用户名字 awk ‘/MA/{print $1}’file1.txt 取root用户的pid awk –F: ‘/root/{print $1 $3}’/etc/passwd 匹配字符串 $1~表示匹配第一个字段 awk –F: ‘$1~/root/{print $3 $1}’/etc/passwd 找到所有uid并求出和 练习: ps aux rss总和? awk取ip地址 ? ifconfig eth2 | awk -F':| +' '/Bcast/{print $4}'
2. 练习
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正则表达式及字符处理 1.使用grep显示出/usr/share/dict/words文件中,例如显示出所有含有fish的行: [root@mycat ~]# grep fish /usr/share/dict/words 2.使用grep显示出/usr/share/dict/words文件中,输出任何包含fish的所有行,还要输出紧接着这行的上下各两行的内容: [root@mycat ~]# grep -C 2 fish /usr/share/dict/words 3. 使用grep显示出/usr/share/dict/words文件中,来显示出在words文件中有多少行含有fish。 [root@manager test5]# grep -c fish /usr/share/dict/words [root@manager test5]# grep fish /usr/share/dict/words | wc -l 4.使用grep显示出/usr/share/dict/words文件中,显示出那些行含有fish,并将行号一块输出,看一看starfish在哪行 [root@manager test5]# grep -n fish /usr/share/dict/words [root@manager test5]# grep -xn starfish /usr/share/dict/words 5.想列出/usr/share/dict/words中包含先有字母t然后有一个元音字母,之后是sh的单词,命令为 [root@manager test5]# grep -x t[aeiou]sh /usr/share/dict/words 6.在/usr/share/dict/words文件中,创建可以符合abominable,abominate,anomie和atomize的正则表达式,但是不要选到别的单词 [root@manager test5]# grep -xE '(abominable|abominate|anomie|atomize)' /usr/share/dict/words [root@manager test5]# grep -xE 'a[bnt]omi(nabl|nat|z)?e' /usr/share/dict/words [root@manager test5]# grep -xE 'a[bnt]omi(na(bl|t)|z)?e' /usr/share/dict/words 7.在/usr/share/dict/words文件中包含多少先有字母t然后有一个元音字母,之后是sh的单词,只输出数量 grep -c t[aeiou]sh /usr/share/dict/words 8.列出/usr/share/dict/words中刚好包含16个字母的单词 [root@manager test5]# grep -xE '[a-zA-Z_]{16}' /usr/share/dict/words [root@manager test5]# grep -xE 'w{16}' /usr/share/dict/words 9.我们将要使用/usr/share/doc文件夹来完成 列出/usr/share/doc/bash-* 文件夹中,所有包含单词expansion的文件 [root@manager test5]# grep -rl "expansion" /usr/share/doc/ 10. 从message里面取出10:00:00-11:20:50这个区间的日志
九、sed使用
1.sed基础
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元字符 . 匹配除换行符之外的任意单个字符,awk中可以匹配换行符 例: abc adc aec a.c *匹配0到多个前边字符 a ab ac abb abc abbc abbbbbbbbbbbc sed 's/ab*/x/' a.txt 匹配a开头b出现0到多次 asdfsdkjfhskc ac asdfjslkfjslfjslfjsfljc a23113131c aacc aaaaaaa1ccccccccc2aaaaaaaaaaa3c4 sed 's/a.*c/x/' a.txt 匹配a0-多个c结尾的字段 *的贪婪性尽可能长的c [...] 匹配方括号中的任意一个字符,^为否定匹配, -表示字符的范围 acc a.c abc a2c a6c a7c a8c sed 's/a.c/x/' a.txt sed 's/a[67c89]c/x/' a.txt sed 's/a[1-9]c/x/' a.txt sed 's/a[^1-9]c/x/' a.txt 1+2 1-2 1*2 1/2 sed 's/1[+-*/]2/x/' a.txt -号报错 sed 's/1[-+*/]2/x/' a.txt ^ 作为正则表达式的第一个字符,匹配行的开始。在awk中可以嵌入 换行符 $ 作为正则表达式的最后一个字符,匹配行的结尾。在awk中可以嵌 入换行符 root aroot roota sed 's/root/x/' a.txt sed 's/^root/x/' a.txt sed 's/root$/x/' a.txt sed 's/^root$/x/' a.txt sed 's/^...$/x/' a.txt 只包含3个字符 sed 's/.../x/' a.txt 最少包含3个字符 sed 's/^$/x/' a.txt sed不能匹配换行符 匹配空行 sed 's/^ *$/x/' a.txt 多个空格的行 {n,m} 匹配出现的n到m次数, {n}匹配出现n次。{n,}匹配至少出现 n次(看扩展) 转义字符 如 a/b sed 's/a/b/x/y/' tt.txt 我们可以替换分隔符 sed 's@a/b@x/y@' tt.txt sed 's;a/b;x/y;' tt.txt 任意的3个字符 都可以 避免产生冲突 date +%Y/%m/%d | sed ‘s@/@:@g’ g全局替换 扩展元字符 + 匹配前面的正则表达式的一次出现或多次出现 a ab abb abbb sed 's/abb*/x/' a.txt sed -r 's/ab+/x/' a.txt ? 匹配前面的正则表达式的零次出现或一次出现 y yes Y Yes sed -r 's/[yY](es)?/x/' a.txt | 可以匹配前面的或后面的正则表达式(替代方案) () 替换方案 对正则表达式分组 company companies compan(y|ies) [abc] (a|b|c) 某些情况下一样 还有分组功能后边会用到 {n,m} 匹配出现的n到m次数, {n}匹配出现n次。{n,}匹配至少出现n次 sed -r 's/a/!/' a.txt 只替换第一次匹配到的 sed -r 's/a{4}/!/' a.txt sed -r 's/a{4,6}/!/' a.txt sed -r 's/a{,4}/!/' a.txt sed -r 's/a{5,}/!/' a.txt 匹配一个字符出现0-1次 基本正则也可以实现 .{,1} sed ‘s/元字符在这里起作用匹配/+-|则不再起元字符作用/’
编写sed脚本 要求如下
原始 完成后
apple banana
banana orange
一条命令完成
是不是我们想的结果?
为什么产生上边的问题:
首先sed在运行中会维护一段内存空间,这段内存空间称为模式空间:
模式空间存储被替换的文件,默认是按行为单位
如上文件读取过程
首先进入模式空间s-----apple 替换为banana
在执行s-----banana 替换为orange
结果apple被替换成orange 没有-n参数 输出终端上
第二条进入模式空间 第一条命令匹配不上,第二条匹配 banana
被替换为orange
寻址上的全局透视(定址)
sed将命令应用于每个输入行,它可以指定零个、一个或两个地址。每个地址
都是一个描述模式、行号或者行寻址符号的正则表达式。(默认全文寻址)
范例file2.txt
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17.TS Beijing,CN .TE Shanghai,CN guangzhou,CN shenyang,CN sed ‘2s/CN/China/’file2.txt #行号定值 sed '/Beijing/s/CN/China/' file2.txt #字符定值 sed ‘$s/CN/China/’file2.txt sed ‘/^.TS/,/^.TE/s/CN/China/’file2.txt #起始,结束定值 sed '4,6s/CN/China/' file2.txt sed '4,$s/CN/China/' file2.txt sed '4,/guangzhou/s/CN/China/' file2.txt
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删除命令d 删除所有的行 d 只删除第一行 1d 使用寻址符号$,删除最后一行 $d 删除空行,正则表达式必须封闭在斜杠//当中 /^$/d 删除.TS 和.TE 标记的tbl 输入 /^.TS/,/^.TE/d 删除第五行到结尾所有的行 5,$d 混合使用行地址和模式地址 $ sed '1,/^$/d' file2.txt 删除除了那些行以外的行 1,5!d 分组命令 .TS Beijing,CN .TE Shanghai,CN guangzhou,CN shenyang,CN sed ‘/^.TS/,/^.TE/s/,/:/ ; /^.TS/,/^.TE/s/CN/China/ file2.txt 使用分组 sed '/^.TS/,/^.TE/{ s/,/:/ ; s/CN/china/ }' file2.txt
练习:
文件:datafile
Steve Blenheim:238-923-7366:95 Latham Lane, Easton, PA 83755:11/12/56:20300
Betty Boop:245-836-8357:635 Cutesy Lane, Hollywood, CA 91464:6/23/23:14500
Igor Chevsky:385-375-8395:3567 Populus Place, Caldwell, NJ 23875:6/18/68:23400
Norma Corder:397-857-2735:74 Pine Street, Dearborn, MI 23874:3/28/45:245700
Jennifer Cowan:548-834-2348:583 Laurel Ave., Kingsville, TX 83745:10/1/35:58900
Jon DeLoach:408-253-3122:123 Park St., San Jose, CA 04086:7/25/53:85100
Karen Evich:284-758-2857:23 Edgecliff Place, Lincoln, NB 92086:7/25/53:85100
Karen Evich:284-758-2867:23 Edgecliff Place, Lincoln, NB 92743:11/3/35:58200
Karen Evich:284-758-2867:23 Edgecliff Place, Lincoln, NB 92743:11/3/35:58200
Fred Fardbarkle:674-843-1385:20 Parak Lane, DeLuth, MN 23850:4/12/23:780900
Fred Fardbarkle:674-843-1385:20 Parak Lane, DeLuth, MN 23850:4/12/23:780900
Lori Gortz:327-832-5728:3465 Mirlo Street, Peabody, MA 34756:10/2/65:35200
Paco Gutierrez:835-365-1284:454 Easy Street, Decatur, IL 75732:2/28/53:123500
Ephram Hardy:293-259-5395:235 CarltonLane, Joliet, IL 73858:8/12/20:56700
James Ikeda:834-938-8376:23445 Aster Ave., Allentown, NJ 83745:12/1/38:45000
Barbara Kertz:385-573-8326:832 Ponce Drive, Gary, IN 83756:12/1/46:268500
Lesley Kirstin:408-456-1234:4 Harvard Square, Boston, MA 02133:4/22/62:52600
William Kopf:846-836-2837:6937 Ware Road, Milton, PA 93756:9/21/46:43500
Sir Lancelot:837-835-8257:474 Camelot Boulevard, Bath, WY 28356:5/13/69:24500
Jesse Neal:408-233-8971:45 Rose Terrace, San Francisco, CA 92303:2/3/36:25000
Zippy Pinhead:834-823-8319:2356 Bizarro Ave., Farmount, IL 84357:1/1/67:89500
Arthur Putie:923-835-8745:23 Wimp Lane, Kensington, DL 38758:8/31/69:126000
Popeye Sailor:156-454-3322:945 Bluto Street, Anywhere, USA 29358:3/19/35:22350
Jose Santiago:385-898-8357:38 Fife Way, Abilene, TX 39673:1/5/58:95600
Tommy Savage:408-724-0140:1222 Oxbow Court, Sunnyvale, CA 94087:5/19/66:34200
Yukio Takeshida:387-827-1095:13 Uno Lane, Ashville, NC 23556:7/1/29:57000
Vinh Tranh:438-910-7449:8235 Maple Street, Wilmington, VM 29085:9/23/63:68900
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
221.把Jon's的名字改成Jonathan. [root@mycat shell]# sed -n "s/Jon's/Jonathan/p" test.txt #-n不输出 p打印 2.删除头三行 [root@mycat shell]# sed '1,3d' test.txt 3.显示5-10行 [root@manager test6]# cat -n test6.txt | sed -n '5,10p' [root@mycat shell]# sed '5,10!d' test.txt 4.删除包含Lane的行. [root@mycat shell]# sed '/Lane/d' test.txt 5.显示所有生日在November-December之间的行 [root@mycat shell]# sed -n '/:1[12]//p' test.txt 6.把三个星号(***)添加到也Fred开头的行 [root@manager test6]# grep Fred test6.txt | sed '/^Fred/s/^/***/' [root@mycat shell]# grep Fred test.txt | sed 's/^Fred/***Fred/' 7.用JOSE HAS RETIRED取代包含Jose的行 [root@manager test6]# grep Jose test6.txt | sed '/Jose/s/.*/JOSE HAS RETIRED/' 8.把Popeye的生日改成11/14/46 [root@manager test6]# grep Popeye test6.txt | sed -r '/Popeye/s@[1]?[0-9]/[1-3]?[0-9]/[0-9][0-9]@11/14/46@' 9.删除所有空白行 [root@manager test6]# sed '/^$/d' test6.txt
替换命令
n 可以是1-512,表示第n次出现的情况进行替换
如:
ababab
sed ‘s/ab/oo/2’ file
g 全局更改
如:
apple apple apple
sed ‘s/apple/ooo/g’file
p 打印模式空间的内容(完成替换后)
如
apple apple apple
123 123 123
sed ‘s/apple/123/p’file.txt
只打印apple行 所以能用-n参数
w file 写入到一个文件file中(只保存替换后行)
如:
sed ‘s/ab/OOO/w a.txt’ test
& 用正则表达式匹配的内容进行替换
n 回调参数 (前边的分组再拿回来)
如:
apple
123
apple
sed ‘s/apple/&&/’a.txt &表示前边的正则表达式 2个&代表输出2次
比如:
this is linux
sed ‘s/linux/& redhat/’file.txt
n如:
$ cat test1
first:second
one:two
$ sed ‘s/(.)????.)/2:1/’ test1
second:first
two:one
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16匹配交换第一第二个字符 sed -r ‘s/(.)(.)/21/’/etc/passwd sed –r ‘s/(.)(.)(.*)/213/’/etc/passwd 1.交换前两个单词 [root@manager test6]# sed -r 's/([a-Z]+)([^a-Z]+)([a-Z]+)(.*)/3214/' test11.txt [root@mycat shell]# sed -r 's/([a-Z]+)([^a-Z]+)([a-Z]+)/321/' aaa.txt [root@mycat shell]# sed -r 's/(.)(..)(.*)/1xx3/' aaa.txt 2.将2.3字符换成xx [root@manager test6]# sed -r 's/(.)(..)(.*)/1XX3/' test11.txt 3.将第一个单词和最后一个单词换位置 [root@manager test6]# sed -r 's/([a-Z]+)([^a-Z]+)(.*)([^a-Z]+)([a-Z]+)/52341/' test11.txt [root@mycat shell]# sed -r 's/([a-Z]+)([^a-Z]+)(.*)([^a-Z]+)([a-Z]+)/52341/' aaa.txt 4.将第一个字符和最后一个单词换位置 [root@manager test6]# sed -r 's/(.)(.*)([^a-Z]+)([a-Z]+)/4231/' test11.txt [root@mycat shell]# sed -r 's/(.)(.*)([^a-Z]+)([a-Z]+)/4231/' aaa.txt
如文件
apple banana egg
一. apple banana egg
apple.Banana egg
apple. Banana egg
apple? Banana egg
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删除 [address]d 删除模式空间的内容,同时改编脚本的控制流,执行这个命令后,在“空 的”模式空间不再有命令执行。删除命令会导致读取新的输入行 sed ‘d;s’ 如果执行了d后边所有命令就不执行了,那么s做什么用? sed ‘/a/d;s 这样如果匹配了a字符 就删除,否则就执行s 这样就构成了一个判断 sed ‘=’a.txt =显示行号 aaaaa bbbbb ccccc dddd sed '/c/d;=' test.txt 追加、插入和更改(a添加 i插入 c更改) [line-address]a text 例: aaaaa bb xx bbb ccccc dddd sed '/xx/a hello' test.txt sed '/xx/i hello' test.txt sed '/xx/c hello' test.txt 以上的操作都是将结果显示在屏幕上:怎么写入到文件 sed –i '/xx/c hello' test.txt -i 直接对源文件做改变 注意文件inode会变化 转换 [address]y/abc/xyz/ sed ‘y/abcdefghijklmnopqrstu…/ABCDEFGHIJKLMNOPQRS…/’a.txt 打印 [address]p 用于输出模式空间的内容 sed ‘’a.txt sed ‘3p’a.txt 打印行号 [line-address]= apple 123 apple sed -n '/apple/{=;p}' test 下一步 [address]n n命令输出模式空间的内容,然后读取输入的下一行,而不用返回脚本的顶端 test aa bb test aa bb sed ‘/test/{n;s/aa/xx}’test.txt 读和写文件 范例文件 file4.txt [line-address]r file [address]w file sed -e '/<mail list>/r maillist' -e '/<mail list>/d' file4.txt /MA$/w region.MA /VA$/w region.VA /CA$/w region.CA 如: test aa bb test aa bb apple banana abc sed '/banana/r aa.txt' tt.txt 退出(速度更快) [line-address]q $ sed '100q' test 测试: for i in {1..100000} do echo $i >> num.txt done time sed –n ‘1,100p’num.txt time sed ‘100q’num.txt
2.高级sed 命令
高级命令分成3个组:
1 处理多行模式空间(N、D、P)
2 采用保持空间来保存模式空间的内容并使它可用于后续的命令
(H、h、G、g)
3 编写使用分支和条件指令的脚本来更改控制流(:、b、t)
高级脚本都做一件共同的事,那就是他们改变了执行或控制的流程顺序。
多行模式空间
追加下一行
多行Next(N)命令通过读取新的输入行,并将它添加到模式空间的现有内容
之后来创建多行模式。
1
2
3
4
5
6
7
8
9
10user1 123 user2 1234 user3 12345 将该文件 用户名,密码追加到一起 每两行合并sed ‘N;s/n/:/’ 3行合并sed ‘N;N;s/n/:/g’
多行删除
D命令删除模式空间中直到第一个换行符的内容。它不会导致读入新的输入行,
相反,它返回到脚本的顶端,将这些指令应用与模式空间剩余的内容。
user1
123
M
user2
1234
W
user3
12345
M
sed ‘/^KaTeX parse error: Undefined control sequence: n at position 7: /{N;/^̲n̲/D}’ user.txt
/^KaTeX parse error: Undefined control sequence: n at position 8: /{ N /^̲n̲/D
}
多行删除命令完成工作的原因是,当遇到两个空行时,D命令只删除两个空行
中的第一个。下一次遍历该脚本时,这个空行将导致另一行被读入模式空间。
如果那行不为空,那么两行都输出,因此确保了输出一个空行。换句话说,当
模式空间中有两个空行时,只有第一个空行被删除。当一个空行后面跟有文本
时,模式空间可以正常输出。
多行
多行打印
P命令输出多行模式空间的第一部分,直到第一个嵌入的换行符为止。在执行
完脚本的最后一个命令之后,模式空间的内容自动输出。
P命令经常出现在N命令之后和D命令之前。
这三个命令能建立一个输入、输出循环,用来维护两行模式空间,但是一次只
输出一行。
这个循环的目的是只输出模式空间的第一行,然后返回到脚本的顶端将所有的
命令应用于模式空间的第二行。
没有这个循环,当执行脚本中的最后一个命令时,模式空间中的这两行都将被
输出。
删除文件倒数第二行
sed ‘N;
!
P
;
D
′
a
.
t
x
t
删
除
文
件
最
后
两
行
s
e
d
′
N
;
!P;D' a.txt 删除文件最后两行 sed 'N;
!P;D′a.txt删除文件最后两行sed′N;!P;
!
D
;
!D;
!D;d’ a.txt
包含
包含那一行
模式空间是容纳当前输入行的缓冲区。还有一个称为保持空间(hode space)
的预留(set-aside)缓冲区。模式空间的内容可以复制到保持空间,而且保持
空间的内容也可以复制到模式空间。有一组命令用于在保持空间和模式空间之
间移动数据。保持空间用于临时存储。单独的命令不能寻址保持空间或者更改
它的内容。
保持空间最常见的用途是,当改变模式空间中的原始内容时,用于保留当
前输入行的副本。
模式空间 保持空间
默认换行符
h—覆盖 全部覆盖
H—追加-> 追加到换行符之后
g覆盖取回–
G追加取回—
例:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
171111111 2222222 利用空间输出 2222222 11111111 sed ‘1h;1d;2G’test.txt 每行加一个空行? 11111 22222 33333 44444 反转 sed '1h;1d;2G;2h;2d;3G;3h;3d;4G' test17.txt sed '1{h;d};2,3{G;h;d};4G' test17.txt sed '1!G;$!h;$!d' test17.txt #多行
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大写转换 样本文件 file6.txt find the Match statement Consult the Get statement. using the Read statement to retrieve data 将 the 和statement之间的单词转换成大写 脚本:changsrc capitalize statement names /the .* statement/{ h s/.*the (.*) statement.*/1/ y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ G s/(.*)n(.*the ).*( statement.*)/213/ } 执行过程: h 将当前输入行复制到保持空间 Pattern Space: find the Match statement Hold Space: find the Match statement s/.*the (.*) statement.*/1/ 取出将被替换的语句 Pattern Space: Match Hold Space: find the Match statement y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/ Pattern Space: MATCH Hold Space: find the Match statement G 将保持空间中的内容追加到模式空间 Pattern Space: MATCHnfind the Match statement Hold Space: find the Match statement s/(.*)n(.*the ).*( statement.*)/213/ 替换并排序 Pattern Space: find the MATCH statement Hold Space: find the Match statement
3.练习
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
561,删除文件每行的第一个字符。 [root@manager zuoye]# sed 's/.//' aa.txt [root@manager zuoye]# sed -r 's/(.)(.*)/2/' aa.txt 2,删除文件每行的第二个字符。 [root@manager zuoye]# sed -r 's/(.)(.)(.*)/13/' aa.txt 3,删除文件每行的最后一个字符。 [root@manager zuoye]# sed -r 's/(.*)(.)$/1/' aa.txt 4,删除文件每行的倒数第二个字符。 [root@manager zuoye]# sed -r 's/(.*)(.)(.)$/13/' aa.txt 5,删除文件每行的第二个单词。 [root@manager zuoye]# sed -r 's/([a-Z]+)([^a-Z]+)([a-Z]+)/12/' aa.txt 6,删除文件每行的倒数第二个单词。 [root@manager zuoye]# sed -r 's/(.*)([^a-Z]+)([a-Z]+)([^a-Z]+)([a-Z]+)/1245/' aa.txt 7,删除文件每行的最后一个单词。 [root@manager zuoye]# sed -r 's/(.*)([^a-Z]+)([a-Z]+)/12/' aa.txt 8,交换每行的第一个字符和第二个字符。 [root@manager zuoye]# sed -r 's/(.)(.)(.*)/213/' aa.txt 9,交换每行的第一个字符和第二个单词。 [root@manager zuoye]# sed -r 's/(.)([a-Z]+)?([^a-Z]+)?([a-Z]+)/4231/' aa.txt 10,交换每行的第一个单词和最后一个单词。 [root@manager zuoye]# sed -r 's/([a-Z]+)([^a-Z]+)(.*)([^a-Z]+)([a-Z]+)/52341/' aa.txt 11,删除一个文件中所有的数字。 [root@manager zuoye]# sed 's/[0-9]//g' aa.txt 12,删除每行开头的所有空格。 [root@manager zuoye]# sed 's/^ *//g' aa.txt 13,用制表符替换文件中出现的所有空格。 [root@manager zuoye]# sed 's/ /t/g' aa.txt 14,把所有大写字母用括号()括起来。 [root@manager zuoye]# sed 's/[A-Z]/(&)/g' /etc/passwd 15,打印每行3次。 [root@manager zuoye]# sed -n 'p;p;p' aa.txt 16,隔行删除 [root@manager zuoye]# cat -n /etc/passwd | sed 'n;d'。 [root@manager zuoye]# cat -n /etc/passwd | sed '1d;n;d' [root@manager zuoye]# cat -n /etc/passwd | sed '0~2d' #起始~步距 [root@manager zuoye]# cat -n /etc/passwd | sed '1~2d' 17,把文件从第22行到第33行复制到第56行后面。 [root@manager zuoye]# cat -n /etc/passwd | sed '22h;23,33H;56G' 18,把文件从第22行到第33行移动到第56行后面。 [root@manager zuoye]# cat -n /etc/passwd | sed '22{h;d};23,33{H;d};56G' 19,只显示每行的第一个单词 [root@manager zuoye]# sed -r 's/([a-Z]+)([^a-Z]+)(.*)/1/' aa.txt 20,打印每行的第一个单词和第三个单词。 [root@manager zuoye]# sed -r 's/([a-Z]+)([^a-Z]+)([a-Z]+)([^a-Z]+)([a-Z]+)(.*)/1:5/' aa.txt 21,将格式为 mm/yy/dd 的日期格式换成 mm;yy;dd [root@manager zuoye]# echo "mm/yy/dd " | sed 's@/@:@g'
十、AWK
AWK是一种优良的文本处理工具。它不仅是 Linux 中也是任何环境中现有的功能最强大的数据处理引擎之一。这种编程及数据操作语言(其名称得自于它的创始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首个字母)的最大功能取决于一个人所拥有的知识。AWK 提供了极其强大的功能:可以进行样式装入、流控制、数学运算符、进程控制语句甚至于内置的变量和函数。它具备了一个完整的语言所应具有的几乎所有精美特性。实际上 AWK 的确拥有自己的语言:AWK 程序设计语言, 三位创建者已将它正式定义为“样式扫描和处理语言”。它允许您创建简短的程序,这些程序读取输入文件、为数据排序、处理数据、对输入执行计算以及生成报表,还有无数其他的功能。
最简单地说, AWK 是一种用于处理文本的编程语言工具。AWK 在很多方面类似于 shell 编程语言,尽管 AWK 具有完全属于其本身的语法。它的设计思想来源于 SNOBOL4 、sed 、Marc Rochkind设计的有效性语言、语言工具 yacc 和 lex ,当然还从 C 语言中获取了一些优秀的思想。在最初创造 AWK 时,其目的是用于文本处理,并且这种语言的基础是,只要在输入数据中有模式匹配,就执行一系列指令。该实用工具扫描文件中的每一行,查找与命令行中所给定内容相匹配的模式。如果发现匹配内容,则进行下一个编程步骤。如果找不到匹配内容,则继续处理下一行。
我们常用sed和awk相结合的方式处理文本sed|awk的方式能让我们的处理命令更快捷,提高工作效率
1.awk语法
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21awk [options] ‘commands’ files option -F 定义字段分隔符,默认的分隔符是连续的空格或制表符 如: aaaa bbbb aaa bb ccc dd awk ‘{print $1}’a.txt awk -F: ‘{print $1}’/etc/passwd 用$1,$2,$3等的顺序表示files中每行以间隔符号分隔的各列不同域.$0代表整行 如: awk ‘{print $1,$2,$0}’a.txt NF变量表示当前记录的字段数 如: awk -F: ‘{print NF}’/etc/passwd awk -F: ‘{print $NF}’/etc/passwd -v可以借用此方式从shell变量中引入 command
读前处理 行处理 读后处理
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
321. 读前处理BEGIN{awk_cmd1;awk_cmd2} 如: awk 'BEGIN {print "hello,World"}' awk 'BEGIN{print "start handle file"}{print}END{print"stop handle file"}' /etc/passwd 练习: 先输出 开始处理文件 取当前系统所有用户的名字 uid 和 shell 最后输出 处理完毕 2. 行处理:定址命令 定址方法: 正则,变量,比较和关系运算 正则需要用//包围起来 awk -F: '/root/{print}' /etc/passwd awk -F: '$1~/root/{print}' /etc/passwd #~是匹配 awk -F: '$1!~/root/{print}' /etc/passwd ^ 行首 $ 行尾 . 除了换行符以外的任意单个字符 * 前导字符的零个或多个 .* 所有字符 [] 字符组内的任一字符 [^]对字符组内的每个字符取反(不匹配字符组内的每个字符) ^[^] 非字符组内的字符开头的行 [a-z] 小写字母 [A-Z] 大写字母 [a-Z] 小写和大写字母 [0-9] 数字 < 单词头单词一般以空格或特殊字符做分隔,连续的字符串被当做单词 > 单词尾 #<root>现在root这个单词
NR变量定址
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
43NR 表示AWK读入的行数 FNR表示读入行所在文件中的行数 # awk '{print NR,FNR,$1}' file1 file2 1 1 aaaaa 2 2 bbbbb 3 3 ccccc 4 1 dddddd 5 2 eeeeee 6 3 ffffff 逻辑运算可直接引用域进行运算 == >= <= != > < # awk 'NR==1 {print}' /etc/passwd root:x:0:0:root:/root:/bin/bash 3.命令{print $0} 4.读后处理END {awk_cmd1;awk_cmd2;} 例子: cat 2.txt | head -2 root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin awk –F”:”‘{print $1,$6}’2.txt | head -2 root /root bin /bin awk –F“:” ‘{print $1”--”$6}’ 2.txt|head -2 #”--”替换分隔符 root /root bin /bin awk –F”:” ‘BEGIN{print “用户名tt家目录”}{print $1”tt”$6}’2.txt| head -2 OFS在BEGIN里面指定分隔符 例2:cat 1.txt mona 70 77 85 83 70 89 john 85 92 78 94 88 91 andrea 89 90 85 94 90 95 jasper 84 88 80 92 84 82 dunce 6 80 60 60 61 62 ellis 5 98 89 96 96 92 awk 'BEGIN{print "tt某某班14暑假成绩n学员t数学t语文t英语t化学t物理t历史"}{print $1"t"$2"t"$3"t"$4"t"$5"t"$6"t"$7}END{print "年级排名请查询数据库"}' test3.txt l awk 'BEGIN{OFS="t";print "tt某某班14暑假成绩";print "学 员t数学t语文t英语t化学t物理t历史"}{print $1,$2,$3,$4,$5,$6,$7}END{print "年级排名请查询数据库"}' test3.txt awk ‘{print $0}’1.txt awk ‘$2~/6/{print $0}’1.txt awk ‘$2>=6{print $0}’1.txt
操作符
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赋值= ++ -- += -= /= *= ++ Add 1 to variable. awk 'BEGIN{a=1;a++;print a}' 打印值为2 awk 'BEGIN{a=1;++a;print a}' 打印值为2 先加1在执行命令 awk 'BEGIN{a=1;print a++;print a}' 先执行命令然后a+1 a=1命令先执行a还=1,最后在打印a=2 -- Subtract 1 from variable. awk ' BEGIN{a=1;a--;print a}' 打印值为0 += Assign result of addition. awk 'BEGIN{a=1;b=a+5;print b}' 给b赋值 awk 'BEGIN{a=1;a=a+5;print a}' 给自己赋值 awk 'BEGIN{a=1;a+=5;print a}' 上条命令简化写法 -= Assign result of subtraction. awk 'BEGIN{a=1;a-=5;print a}' a-5在赋值给a 以下相同 awk 'BEGIN{a=1;a-=5.2;print a}' 支持小数运算 *= Assign result of multiplication. /= Assign result of division. %= Assign result of modulo. ^= Assign result of exponentiation || Logical OR 逻辑 两边任意一边成立 && Logical AND 逻辑与 两边成立 前边如果假值后边就不做了 ! Logical NOT 逻辑取反 原本真值变成假值 例如: awk '$1~/root/||NR>40{print}' /etc/passwd awk '$1~/root/&&NR<2{print}' /etc/passwd 匹配正则或不匹配,正则需要用/正则/ 包围住 ~ !~ 关系比较字符串时要把字符串用双引号引起来 < <= > >= != == 字段引用 $ 字段引用需要加$,而变量引用直接用变量名取 运算符+ - * / % ++ --
转义序列
1
2
3
4
5
6
7
8
9
10
11自身 $ 转义$ t 制表符 b 退格符 r 回车符 n 换行符 c 取消换行 awk引用shell变量 a=root awk –v var=$a –F“:” ’$1==var{print $0}’ /etc/passwd
内置变量
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
52FS 定义字段分隔符,默认为一个空格 #读入分隔符 OFS 输出的字段分隔符,默认为一个空格 #输出分隔符 awk 'BEGIN{ FS=":";OFS="-" }{ print $1,$3,$5 }' /etc/passwd | head -2 awk 'BEGIN{ FS=":";OFS="-" }{ print $1”@@”$3”##”$5 }' /etc/passwd | head -2 自己定义 RS 记录分隔符,默认为一个换行符 head -2 /etc/passwd | awk 'BEGIN{ RS=":"}{print}' ORS 输出的记录分隔符,默认为一个换行符 head -2 /etc/passwd | awk 'BEGIN{ ORS="-"}{print}' NR 行数(如两个文件一个5行 1个10行 输出为15行) awk '{print NR}' aa.txt cc.txt FNR 行数,多文件操作时会重新排序(如两个文件一个5行,一个10行 输出为5 10) awk '{print FNR}' aa.txt cc.txt NF 输出当前输入记录的编号(字段的个数) aaaa bbb ccc cccc bbb aaa ccc bb nn awk '{ print NF}' aa.txt FILENAME 文件名 ARGC 命令行参数个数 ARGV 命令行参数排列 ENVIRON 输出系统环境变量 例子: cat awk.txt aaa#123 asdf:234 haha:456 awk –F’#’ ’{print NR,$0,NF,FILENAME }’awk.txt 1 aaaa#123 2 awk.sh 2 asdf:234 1 awk.sh 3 haha:456 1 awk.sh 4 0 awk.sh awk -F"#" '{ print ARGC,ARGV[0],ARGV[1]}' awk.sh.txt 2 awk awk.sh.txt 2 awk awk.sh.txt 2 awk awk.sh.txt 2 awk awk.sh.txt awk -F"#" '{ print NR,$0,NF,$1,$2 }' awk.sh.txt 1 aaaa#123 2 aaaa 123 2 asdf:234 1 asdf:234 3 haha:456 1 haha:456 4 0 awk 'BEGIN{print ENVIRON["USER"]}'
练习题:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
191打印uid在30~40范围内的用户名 [root@mycat shell]# awk -F":" '$3>=30&&$3<=40{print $1,$3}' /etc/passwd 2打印第5-10行的行号和用户名 [root@mycat shell]# awk 'NR>=5&&NR<=10{print NR,$1}' /etc/passwd 3 打印奇数行 [root@mycat shell]# awk 'NR%2==1{print NR,$0}' /etc/passwd 4 打印偶数行 [root@mycat shell]# awk 'NR%2==0{print NR,$0}' /etc/passwd 5 打印字段数大于5的行 [root@mycat shell]# awk -F":" 'NF>5{print $0}' /etc/passwd 6打印UID不等于GID的用户名 [root@mycat shell]# awk -F":" '$3!=$4{print $0}' /etc/passwd 7.打印1..100以内的7的倍数和包含7的数 seq 1 100 | awk '$1~/7/||$1%7==0{print $1}' 8.计算UID相加的总和;计算GID相加的总和 [root@mycat shell]# awk -F: '{uid+=$3;gid+=$4}END{print uid;print gid}' /etc/passwd 9.计算VSZ和RSS各自的和 并以M单位显示 [root@mycat shell]# ps aux|awk 'NR>1{vsz+=$5;rss+=$6}END{print vsz/1024"M";print rss/1024"M"}'
2.流程控制
分支结构
一. if (条件) 动作
若有多个动作,则要用大括号将动作体包含起来if (条件) {动作1;动作2}
1
2
3awk -F : '{if ($1 == "root") print $1}' /etc/passwd awk -F: '{if ($1 == "root") {print $1;print $6} }' /etc/passwd
二.
if(条件1)
动作1
else
动作2
1
2
3awk -F: '{if ($1 == "root"){print $1}else print $6}' /etc/passwd awk -F: '{if ($1 == "root") print $1;else print $6}' /etc/passwd
上面两个命令是等价的,要么用分号隔开,表示第一个动作体的结束,要么将动作体用大括号定位范围
三.
if (条件1)
动作1
else if(条件2)
动作2
else if(条件3)
动作3
else
动作
1
2
3
4
5
6
7
8
9awk -F: '{if ($1 == "root") print $1;else if ($1 == "seker") print $6;else if ($1 == "zorro") print $7;else printNR}' /etc/passwd 读前处理和读后处理 awk -F: 'BEGIN {print NR,NF}' /etc/passwd 0 0 awk -F: 'END {print NR,NF}' /etc/passwd 46 7 awk -F: 'BEGIN{i=1} {i++} END {print i}' /etc/passwd 47
练习:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18找出普通用户的用户名并统计数量 [root@mycat shell]# awk -F: '{if($3>=1000) {print $1;sum++}END{print sum}' /etc/passwd 将系统用户按UID分组标记 0 admin; 1-499 sysuser; 1000+ users 用户名 uid 权限 root 0 admin ftp 21 sysuser robin 500 users [root@manager test7]# awk 'BEGIN{FS=":";OFS="t";print "用户名tUIDt权限"}{if($3==0)print $1,$3,"admin";else if($3<500)print $1,$3,"sysusers";else print $1,$3,"users"}' /etc/passwd awk 'BEGIN{OFS="t";print "名字t语文t数学t英语t历史t物理t生物t总成绩t平均t评价"}{sum=$2+$3+$4+$5+$6+$7;if(sum/6>=90)print $1,$2,$3,$4,$5,$6,$7,sum,sum/6,"优秀";else if(sum/6>=80)print $1,$2,$3,$4,$5,$6,$7,sum,sum/6,"良好";else if(sum/6>=70)print $1,$2,$3,$4,$5,$6,$7,sum,sum/6,"一般";else print $1,$2,$3,$4,$5,$6,$7,sum,sum/6,"烂"}END{print "某某班级期中成绩"}' chengji.txt
循环语句
while(条件) {
动作
条件运算
1
2
3
4
5
6
7awk -F: '{while($3<3) {print $3,$1;$3++}}' /etc/passwd BEGIN块可以独立使用,不需要引入文件 awk 'BEGIN{i=1;while(i<100) {print i;i++}}' 练习 打印100以内的偶数 awk 'BEGIN{i=1;while(i<100){if(i%2==0)print i;i++}}' x=1
do {
动作1
x++
} while (x<5)
1
2
3awk 'BEGIN{i=5;do{print i;i++}while(i<10)}' awk 'BEGIN{i=5;do{print i;i++}while(i<1)}'
for(预置;条件;递增) {
动作
}
1
2
3
4
5
6
7
8
9
10
11
12
13awk 'BEGIN {for (x=1;x<=4;x++) print x }' 练习: 逆序输出每个字段 达到这样既可 /bin/bash /root root 0 0 x root awk -F: 'BEGIN{printf "%-15s %-15s %-15sn","用户名","UID","权限"}{if ($3==0) printf "%-18s %-15s %-15sn",$1,$3,"admin";else if($3<500) printf "%-18s %-15s %-15sn",$1,$3,"sysuser";else printf "%-18s %-15s %-15sn",$1,$3,"users"}' /etc/passw
跳转语句
break 跳出循环
continue 在达到循环底部之前终止当前循环从新开始下一次循环
next 读入下一行同时返回脚本顶部这样可以避免对当前行执行其他操作
1
2
3
4awk 'BEGIN {for(x=1;x<5;x++) {if (x==3) break;print x }}' awk 'BEGIN {for(x=1;x<5;x++) {if (x==3) continue;print x }}' awk -F: 'NR > 5 {next} {print $1} END {print NR}' /etc/passwd
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25cat -b u.txt 1 root:x:0:0:root:/root:/bin/bash 2 bin:x:1:1:bin:/bin:/sbin/nologin 3 daemon:x:2:2:daemon:/sbin:/sbin/nologin 4 adm:x:3:4:adm:/var/adm:/sbin/nologin 5 lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin 6 sync:x:5:0:sync:/sbin:/bin/sync 7 shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown 8 halt:x:7:0:halt:/sbin:/sbin/halt 9 mail:x:8:12:mail:/var/spool/mail:/sbin/nologin 10 news:x:9:13:news:/etc/news: awk -F: 'BEGIN{i=1}NR>5 {next}{print i++}END{print NR}' u.txt 1 2 3 4 5 10 awk -F: 'BEGIN{i=1}NR>5 {exit}{print i++}END{print NR}' u.txt 1 2 3 4 5
3.数组
自定义数组
1
2
3
4
5
6awk 'BEGIN {ary[1]="seker";ary[2]="zorro";print ary[1],ary[2]}' seker zorro awk 'BEGIN {ary[1]="seker";ary[2]="zorro";for(i in ary) print ary[i]}' seker zorro
循环产生数组和取出数组
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25awk 'BEGIN{n=5;for (i=1;i<=n;i++) ary[i]=i+100;for(m in ary) print m,ary[m]}' 4 104 5 105 1 101 2 102 3 103 awk -F: '{ary[NR]=$1} END {for(i in ary) print i,ary[i]}' /etc/passwd 1 root 2 bin 3 daemon 4 adm 5 lp 6 sync 7 shutdown 8 halt 9 mail awk -F: '{ary[$3]=$1} END {for(i in ary) print i,ary[i]}' /etc/passwd 10 uucp 11 operator 12 games 13 gopher 14 ftp 32 rpc 37 rpm
利用数组实现行列互换?
如
1
2
3
4
5
6
7
8
9
10
11
12
13[root@manager ~]# cat aa.txt 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 5 5 5 5 5 [root@manager test7]# awk '{for(i=1;i<=NF;i++) ary[NR,i]=$i}END{for(j=1;j<=NF;j++){for(l=1;l<=NR;l++)printf ary[l,j]" ";printf "n"}}' kk.txt
4.awk的内置函数
一.算数函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18sqrt函数(求平方根) [root@manager ~]# awk 'BEGIN{x=sqrt(100);print x}' 10 [root@manager ~]# awk 'BEGIN{x=int(3.14);print x}' 3 [root@manager ~]# awk 'BEGIN{x=int(3.88);print x}' 3 rand函数(内置函数 srand 使用参数awk 'BEGIN{x=rand();print x}'作为随机数种子。当参数缺省的时候,使用当前时间作为随机数种子。) [root@manager ~]# awk 'BEGIN{x=rand();print x}' 0.237788 srand函数(内置函数 rand 的伪随机函数,其返回值范围为 0 >= result <= 1。在实际使用时,一般先使用 srand 函数生成随机数种子,然后再使用 rand 函数生成随机数。否则每次得到的值会一样。) [root@manager ~]# awk 'BEGIN{srand();x=int(100*rand());print x}' 64 [root@manager ~]# awk 'BEGIN{srand();x=int(100*rand());print x}' 32 [root@manager ~]# awk 'BEGIN{srand();x=int(100*rand());print x}' 60
二.字符串函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23sub和gsub函数使用(替换字符) [root@manager ~]# awk 'BEGIN{info="this is a test2010test2010test!";sub(2010,"!",info);print info}' this is a test!test2010test! [root@manager ~]# awk 'BEGIN{info="this is a test2010test2010test!";gsub(2010,"!",info);print info}' this is a test!test!test! index函数(查找字符) [root@manager ~]# awk 'BEGIN{info="this is test2010test!";print index(info,"test")?"ok":"not found";}' ok length函数(计算长度) [root@manager ~]# awk 'BEGIN{info="hello";print length(info)}' 5 substr函数(截取字符串) [root@manager ~]# awk 'BEGIN{info="hello world";print substr(info,4,10)}' lo world match函数(正则匹配查找) [root@manager ~]# awk 'BEGIN{info="hello 2016world";print match(info,/[0-9]+/)?"ok":"none";}' ok split函数(字符分割) [root@manager ~]# awk 'BEGIN{info="hello world";split(info,test);print length(test);for(k in test){print k,test[k];}}' 2 1 hello 2 world
三.一般函数
函数 | 说明 |
---|---|
close( Expression ) | 用同一个带字符串值的 Expression 参数来关闭由 print 或 printf 语句打开的或调用 getline 函数打开的文件或管道。如果文件或管道成功关闭,则返回 0;其它情况下返回非零值。如果打算写一个文件,并稍后在同一个程序中读取文件,则 close 语句是必需的。 |
system(Command ) | 执行 Command 参数指定的命令,并返回退出状态。等同于 system 子例程。 |
Expression | getline [ Variable ] | 从来自 Expression 参数指定的命令的输出中通过管道传送的流中读取一个输入记录,并将该记录的值指定给 Variable 参数指定的变量。如果当前未打开将 Expression 参数的值作为其命令名称的流,则创建流。创建的流等同于调用 popen 子例程,此时 Command 参数取 Expression 参数的值且 Mode 参数设置为一个是 r 的值。只要流保留打开且 Expression 参数求得同一个字符串,则对 getline 函数的每次后续调用读取另一个记录。如果未指定 Variable 参数,则 $0 记录变量和 NF 特殊变量设置为从流读取的记录。 |
getline [ Variable ] < Expression | 从 Expression 参数指定的文件读取输入的下一个记录,并将 Variable 参数指定的变量设置为该记录的值。只要流保留打开且 Expression 参数对同一个字符串求值,则对 getline 函数的每次后续调用读取另一个记录。如果未指定 Variable 参数,则 $0 记录变量和 NF 特殊变量设置为从流读取的记录。 |
getline [ Variable ] | 将 Variable 参数指定的变量设置为从当前输入文件读取的下一个输入记录。如果未指定 Variable 参数,则 $0 记录变量设置为该记录的值,还将设置 NF、NR 和 FNR 特殊变量。 |
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
42close函数 [root@manager ~]# awk 'BEGIN{while("head -5 /etc/passwd"|getline){print $0;};close("/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 getline函数 #输入 [root@manager ~]# awk 'BEGIN{while(getline < "/etc/passwd"){print $0;};close("/etc/passwd");}' [root@manager ~]# awk 'BEGIN{print "Enter your name:";getline name;print name;}' Enter your name: robin robin [root@manager ~]# awk 'BEGIN{printf "Enter your name:";getline name;print name;}' Enter your name:robin robin [root@manager test7]# awk -F: 'BEGIN{printf "输入用户名: ";getline name;while(getline < "/etc/passwd"){if($1==name) print $0}}' system函数 #调用系统指令 [root@manager ~]# awk 'BEGIN{b=system("ls -l /root");print b;}' 总用量 20 -rw-r--r-- 1 root root 135 9月 18 16:14 aa.txt -rw-------. 1 root root 905 9月 9 06:30 anaconda-ks.cfg -rw-r--r--. 1 root root 8003 9月 9 06:30 install.log -rw-r--r--. 1 root root 3384 9月 9 06:30 install.log.syslog 0 [root@manager test7]# awk -F: 'BEGIN{x=system("id robin &>/dev/null");if(x==0){while(getline < "/etc/passwd")if($1=="robin")print $1,$6}}' robin /home/robin
四.时间函数
函数名 | 说明 |
---|---|
mktime( YYYY MM DD HH MM SS[ DST]) | 生成时间格式 |
strftime([format [, timestamp]]) | 格式化时间输出,将时间戳转为时间字符串 具体格式,见下表 |
systime() | 得到时间戳,返回从1970年1月1日开始到当前时间(不计闰年)的整秒数 |
创建时间格式
1
2
3
4
5
6
7
8[root@manager ~]# awk 'BEGIN{tstamp=mktime("2001 01 01 12 12 12");print strftime("%c",tstamp);}' 2001年01月01日 星期一 12时12分12秒 [root@manager ~]# awk 'BEGIN{tstamp1=mktime("2001 01 01 12 12 12");tstamp2=mktime("2001 02 01 0 0 0");print tstamp2-tstamp1;}' 2634468 [root@manager ~]# awk 'BEGIN{tstamp1=mktime("2001 01 01 12 12 12");tstamp2=systime();print tstamp2-tstamp1;}' 495876393
strftime日期和时间格式说明符
格式 | 描述 |
---|---|
%a | 星期几的缩写(Sun) |
%A | 星期几的完整写法(Sunday) |
%b | 月名的缩写(Oct) |
%B | 月名的完整写法(October) |
%c | 本地日期和时间 |
%d | 十进制日期 |
%D | 日期 08/20/99 |
%e | 日期,如果只有一位会补上一个空格 |
%H | 用十进制表示24小时格式的小时 |
%j | 从1月1日起一年中的第几天 |
%m | 十进制表示的月份 |
%M | 十进制表示的分钟 |
%p | 12小时表示法(AM/PM) |
%S | 十进制表示的秒 |
%U | 十进制表示的一年中的第几个星期(星期天作为一个星期的开始) |
%w | 十进制表示的星期几(星期天是0) |
%W | 十进制表示的一年中的第几个星期(星期一作为一个星期的开始) |
%x | 重新设置本地日期(08/20/99) |
%X | 重新设置本地时间(12:00:00) |
%y | 两位数字表示的年(99) |
%Y | 当前月份 |
%Z | 时区(PDT) |
%% | 百分号(%) |
printf函数
是格式化输出函数, 一般用于向标准输出设备按规定格式输出信息。在编写程序时经常会用到此函数。printf()函数的调用格式为:
%d 十进制有符号整数
%u 十进制无符号整数
%f 浮点数
%s 字符串
%c 单个字符
%p 指针的值
%e 指数形式的浮点数
%x, %X 无符号以十六进制表示的整数
%o 无符号以八进制表示的整数
%g 自动选择合适的表示法
n 换行
f 清屏并换页
r 回车
t Tab符
xhh 表示一个ASCII码用16进表示,其中hh是1到2个16进制数
输出样式
%s是字符类型,%d数值类型
printf默认是不输出换行的所以要加n
10和7是偏移量
默认是右对齐,所有加个- 就是左对齐,就是把不足的位数用空格填充
注意:格式与输出列之间要有逗号
[root@manager ~]# awk ‘BEGIN{a=16;printf “%-10on”,a}’
20
1.使用awk打印一个用星号组成金字塔
2.使用awk打印99乘法表
3.输出100-999
1-9 0-9 0-9
4.开两个虚拟机,定时(10分钟)将虚拟机的httpd日志收集到本机,提取,这些httpd日志的 ip 访问时间 浏览器 保存到文件
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练习1答案 1. awk -F: '$3>=30&&$3<=40 {print NR, $1}' passwd 2. awk -F: 'NR>=5&&NR<=10 {print NR, $1}' passwd 3. awk -F: 'NR%2!=0 {print}' passwd 4. awk -F: 'NR%2==0 {print}' passwd 5. awk -F: 'NF>5 {print NR}' passwd 6. awk -F: '$3!=$4 {print $3,$4}' passwd 7. seq 100 | awk '$0%7==0 || $0 ~/7/ {print $0}' | head -3 8. awk -F: 'BEGIN{i=0}{sum+=$3;gsum+=$4;i++}END{print i;print sum;print gsum}' /etc/passwd 9. ps aux | awk 'BEGIN{i=0}NR>=2{vsum+=$5;rsum+=$6;i++}END{print vsum/1024"M";print rsum/1024"M";print i}' 练习2: 练习找出普通用户的用户名并统计数量 awk -F: 'BEGIN{i=0} $3>=500 {print $1;i++} END {print i}' /etc/passwd awk -F: '{if($3==0) print $1"t"$3"t""admin";else if($3>=1&&$3<500) print $1,$3,"sysuser";else print $1,$3,"user"}' /etc/passwd 练习打印100以内的偶数 # awk 'BEGIN{i=1;while(i<100) {if (i%2==0) print i;i++}}' 逆序输出每个字段 达到这样既可 /bin/bash /root root 0 0 x root # awk -F: '{for (x=NF;x>0;x--) print $x}' /etc/passwd 输出样式 %s是字符类型,%d数值类型 printf默认是不输出换行的所以要加n 10和7是偏移量 默认是右对齐,所有加个- 就是左对齐,就是把不足的位数用空格填充 注意:格式与输出列之间要有逗号 # awk -F: '{printf "%-10s %-10d %sn",$1,$3,$7}' /etc/passwd 继续解决上一个试做题的格式问题 # awk -F: '/bash$/{for (x=NF;x>0;x--) printf "%-13s",$x;printf "n"}' /etc/passwd 使用嵌套的for循环,打印100-999之间的数,个十百位分别用一个for来打印 # awk 'BEGIN{OFS="";for (i=1;i<=9;i++) {for (j=0;j<=9;j++) {for (n=0;n<=9;n++) print i,j,n}}}' 打印乘法口诀表 # cat 99.sh #!/bin/bash awk 'BEGIN{ for(i=1;i<10;i++) { for(j=1;j<=i;j++) printf "%d*%d=%d ",j,i,j*i print } }' # 打印金字塔 # cat jin.sh #!/bin/bash awk 'BEGIN{ num=5 for(i=1;i<=num;i++) { for (n=1;n<=num-i;n++) printf "%s"," " for (j=1;j<=2*i-1;j++) printf "%s","*" print } }' [root@manager ~]# awk '{for(i=1;i<=NF;i++) ary[NR,i]=$i}END{for(j=1;j<=NF;j++){for(k=1;k<=NR;k++)printf ary[k,j]" ";printf "n"}}' aa.txt 1 1 1 1 1 2 2 2 2 2 3 3 3 3 3 4 4 4 4 4 5 5 5 5 5 [root@manager ~]# cat aa.txt 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5 1 2 3 4 5
最后
以上就是英俊画笔最近收集整理的关于shell脚本shell脚本的全部内容,更多相关shell脚本shell脚本内容请搜索靠谱客的其他文章。
发表评论 取消回复