Shell脚本
一、shell脚本是什么
编程语言分类:
编译型语言
程序在执行之前需要一个专门的编译过程,把程序编译成为机器语言文件,运行时不需要重新翻译,直接使用编译的结果就行了。程序执行效率高,依赖编译器,跨平台性差些。如C、C++、java
解释型语言
程序不需要编译,程序在运行时由解释器翻译成机器语言,每执行一次都要翻译一次。因此效率比较低。比如Python/JavaScript/ Perl /ruby/Shell等都是解释型语言。
通过shell语言将完成一个任务的所有代码写入一个文件,并给执行权限。shell是一个程序,采用C语言编写,是用户和linux内核沟通的桥梁。它既是一种命令语言,又是一种解释性的编程语言。
按照顺序执行。它是解释型的,意味着不需要编译
二、shell脚本的优势
解放运维人员:7X24小时监控,监控为例,监控帮你干活,你只需要处理问题就好。
提升业务能力:业务初始化,自动备份,日志分析,你的工作脚本来做,效率更高。
提升管理能力:从系统安装到业务部署,再到服务器管理维护,实现自动化运维,批量管理机器与业务。
shell的作用是
解释执行用户输入的命令或者程序等
用户输入一条命令,shell脚本就解释一条
键盘输入命令,linux给出响应的方式,称之为交互式。
若干命令 + 脚本的基本格式 + 脚本特定语法 + 思想= shell脚本
脚本命令演示创建一个用户:harry useradd harry密码设置为:yunwei.98989 echo \"yunwei.98989\"|passwd --stdin harry该用户创建文件夹/tmp/zutuanxue mkdir /tmp/zutuanxue该用户创建文件/tmp/zutuanxue/README touch /tmp/zutuanxue/README将“hello world“输入到/tmp/zutuanxue/README echo \'hello world\' > /tmp/zutuanxue/README实现代码 01_task.sh#!/bin/bash#main #创建用户harryuseradd harry#设置用户密码 yunwei.98989echo \"yunwei.98989\"|passwd --stdin harry#使用harry创建文件夹,文件,输入文件中内容su - harry -c \"mkdir /tmp/zutuanxue\"su - harry -c \"touch /tmp/zutuanxue/README\"su - harry -c \"echo \'hello world\' > /tmp/zutuanxue/README\"1、#!/bin/bash//脚本第一行, #!魔法字符,指定脚本代码执行的程序。即它告诉系统这个脚本需要什么解释器来执行,也就是使用哪一种Shell2、#代表注释,#!特例
脚本执行方法
[root@zutuanxue shell01]# cat 1.sh #!/bin/bash#xxxx#xxx#xxxhostnamedate[root@zutuanxue shell01]# chmod +x 1.sh [root@zutuanxue shell01]# lltotal 4-rwxr-xr-x 1 root root 42 Jul 22 14:40 1.sh[root@zutuanxueshell01]# /shell/shell01/1.sh zutuanxueSun Jul 22 14:41:00 CST 2018[root@zutuanxue shell01]# ./1.sh zutuanxueSun Jul 22 14:41:30 CST 2018[root@zutuanxue shell01]# bash -x 1.sh+ hostnamezutuanxue+ dateSun Jul 22 14:43:20 CST 2018-x:一般用于排错,查看脚本的执行过程-n:用来查看脚本的语法是否有问题注意:如果脚本没有加可执行权限,不能使用标准的执行方法执行,bash 1.sh其他:[root@zutuanxueshell01]# source 2.shserverThu Nov 22 15:45:50 CST 2018[root@zutuanxue shell01]# . 2.shserverThu Nov 22 15:46:07 CST 2018source 和 . 表示读取文件,执行文件里的命令
– 命令式脚本执行方法:
定义命令路径变量 PATHPATH=$PATH:脚本路径备注:脚本必须给执行权限
三、shell脚本的应用
重点:重复性的工作,全部通过脚本来完成。高效的同时还不出错。
根据企业架构自定义监控系统,量身打造企业级监控系统
业务初始化部署系统,业务初始化全部一键搞定,省去繁琐的安装与排错
一键备份,分分钟搞定备份问题
日志分析,繁琐又复杂的日志分析让机器取做吧。
三方软件模块插件的编写:根据业务定制三方软件的功能,更贴合自己的业务。
四、相关命令
数据检索命令
行检索: grep egrep; 字符串检索:cut tr
数据处理命令
数据排序:sort ; 数据去重:uniq; 文本数据合并:paste ; 数据输出:tee ; 数据处理:xargs
1、grep: 负责从数据源中检索对应的字符串,行过滤。
grep用于根据关键字进行行过滤grep options \'keys\' filenameOPTIONS: -i: 不区分大小写 -v: 查找不包含指定内容的行,反向选择 -w: 按单词搜索 -n: 显示行号 -A: 显示匹配行及后面多少行 -A 5 -B: 显示匹配行及前面多少行 -o: 打印匹配关键字 -c: 统计匹配到的次数 -r: 逐层遍历目录查找 -C: 显示匹配行前后多少行 -l:只列出匹配的文件名 -L:列出不匹配的文件名 -e: 使用正则匹配 -E:使用扩展正则匹配 ^key:以关键字开头 key$:以关键字结尾 ^$:匹配空行 --color=auto :可以将找到的关键词部分加上颜色的显示常用命令选项必知必会 示例:# grep -i root passwd 忽略大小写匹配包含root的行# grep -w ftp passwd 精确匹配ftp单词# grep -wo ftp passwd 打印匹配到的关键字ftp# grep -n root passwd 打印匹配到root关键字的行好# grep -ni root passwd 忽略大小写匹配统计包含关键字root的行# grep -nic root passwd 忽略大小写匹配统计包含关键字root的行数# grep -i ^root passwd 忽略大小写匹配以root开头的行# grep bash$ passwd 匹配以bash结尾的行# grep -n ^$ passwd 匹配空行并打印行号# grep ^# /etc/vsftpd/vsftpd.conf 匹配以#号开头的行# grep -v ^# /etc/vsftpd/vsftpd.conf 匹配不以#号开头的行# grep -A 5 mail passwd 匹配包含mail关键字及其后5行# grep -B 5 mail passwd 匹配包含mail关键字及其前5行# grep -C 5 mail passwd 匹配包含mail关键字及其前后5行centos8中已经为大家设置了,存放在/etc/profile.d/colorgrep.sh文件中,如若大家使用的系统中没有设置颜色输出,可以使用以下方法来自行设置临时设置:# alias grep=\'grep --color=auto\' //只针对当前终端和当前用户生效永久设置:1)全局(针对所有用户生效)vim /etc/bashrcalias grep=\'grep --color=auto\'source /etc/bashrc2)局部(针对具体的某个用户)vim ~/.bashrcalias grep=\'grep --color=auto\'注意:如果希望你对环境变量的设置立刻生效,可以使用以下命令而不需要重启计算机source ~/.bashrc
2、cut数据截取
cut用于列截取-c: 以字符为单位进行分割。-d: 自定义分隔符,默认为制表符。\\t-f: 与-d一起使用,指定显示哪个区域。# cut -d: -f1 1.txt 以:冒号分割,截取第1列内容# cut -d: -f1,6,7 1.txt 以:冒号分割,截取第1,6,7列内容# cut -c4 1.txt 截取文件中每行第4个字符# cut -c1-4 1.txt 截取文件中每行的1-4个字符# cut -c4-10 1.txt # cut -c5- 1.txt 从第5个字符开始截取后面所有字符
3、tr 字符转换:替换,删除
tr用来从标准输入中通过替换或删除操作进行字符转换;主要用于删除文件中控制字符或进行字符转换。使用tr时要转换两个字符串:字符串1用于查询,字符串2用于处理各种转换。语法:commands|tr \'string1\' \'string2\'tr \'string1\' \'string2\' < filenametr options \'string1\' < filename-d 删除字符串1中所有输入字符。-s 删除所有重复出现字符序列,只保留第一个;即将重复出现字符串压缩为一个字符串。a-z 任意小写A-Z 任意大写0-9 任意数字[root@zutuanxue shell01]# cat 3.txt 自己创建该文件用于测试ROOT:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologinadm:x:3:4:adm:/var/adm:/sbin/nologinlp:x:4:7:lp:/var/spool/lpd:/sbin/nologinsync:x:5:0:sync:/sbin:/bin/syncshutdown:x:6:0:shutdown:/sbin:/sbin/shutdownhalt:x:7:0:halt:/sbin:/sbin/haltmail:x:8:12:mail:/var/spool/mail:/sbin/nologinuucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologinboss02:x:516:511::/home/boss02:/bin/bashvip:x:517:517::/home/vip:/bin/bashstu1:x:518:518::/home/stu1:/bin/bashmailnull:x:47:47::/var/spool/mqueue:/sbin/nologinsmmsp:x:51:51::/var/spool/mqueue:/sbin/nologinaaaaaaaaaaaaaaaaaaaabbbbbb111111122222222222233333333cccccccchello world 888666777999# tr -d \'[:/]\' < 3.txt 删除文件中的:和/# cat 3.txt |tr -d \'[:/]\' 删除文件中的:和/# tr \'[0-9]\' \'@\' < 3.txt 将文件中的数字替换为@符号# tr \'[a-z]\' \'[A-Z]\' < 3.txt 将文件中的小写字母替换成大写字母# tr -s \'[a-z]\' < 3.txt 匹配小写字母并将重复的压缩为一个# tr -s \'[a-z0-9]\' < 3.txt 匹配小写字母和数字并将重复的压缩为一个
4、sort排序
sort:将文件的每一行作为一个单位,从首字符向后,依次按ASCII码值进行比较,最后将他们按升序输出。语法:sort [options] [filename]-u :去除重复行-r :降序排列,默认是升序-o : 将排序结果输出到文件中 类似 重定向符号 >-n :以数字排序,默认是按字符排序-t :分隔符-k :第N列-b :忽略前导空格。-R :随机排序,每次运行的结果均不同。 示例:# sort -n -t: -k3 1.txt 按照用户的uid进行升序排列# sort -nr -t: -k3 1.txt 按照用户的uid进行降序排列# sort -n 2.txt 按照数字排序# sort -nu 2.txt 按照数字排序并且去重# sort -nr 2.txt # sort -nru 2.txt # sort -nru 2.txt # sort -n 2.txt -o 3.txt 按照数字排序并将结果重定向到文件# sort -R 2.txt # sort -u 2.txt
5、uniq 去除连续的重复行
应用技巧:去重前先使用sort排序
uniq:去除连续重复行语法:uniq [options] [filename]-i: 忽略大小写-c: 统计重复行次数-d:只显示重复行# uniq 2.txt # uniq -d 2.txt # uniq -dc 2.txt
6、tee 双向输出
tee工具从标准输入读取并写入标准输出和文件,即:双向覆盖重定向somecommand |tee filename-a 双向追加重定向# echo hello world# echo hello world|tee file1# cat file1 # echo 999|tee -a file1# cat file1
7、paste
paste工具用于合并文件行输出到屏幕,不会改动源文件-d:自定义间隔符,默认是tab,只接受一个字符-s:将每个文件中的所有内容按照一行输出,文件中的行与行以TAB间隔。[root@zutuanxue shell01]# cat a.txt hello[root@zutuanxue shell01]# cat b.txt hello world888999[root@zutuanxue shell01]# paste a.txt b.txt hello hello world 888 999[root@zutuanxue shell01]# paste b.txt a.txt hello world hello888999[root@zutuanxue shell01]# paste -d\'@\' b.txt a.txt hello world@hello888@999@[root@zutuanxue shell01]# paste -s b.txt a.txt hello world 888 999hello
8、xargs 上一个命令的输出作为下一个命令的命令行参数
管道(|):上一个命令的输出作为下一个命令的输入,做的是数据源。
[root@manage01 ~]# sort -n 2.txt |uniq 1235610999999如何将上一个命令的输出,作为下一个命令的参数呢?xargs 上一个命令的输出作为下一个命令的命令行参数回顾:linux 命令格式命令 命令选项 参数ls -l /========================xargs 可以将管道或标准输入(stdin)数据转换成命令行参数,也能够从文件的输出中读取数据。xargs 一般是和管道一起使用。命令格式:\'\'[somecommand]|[filename]\'\' |xargs -item commandOPTIONS:-a file 从文件中读入作为sdtin-E flag flag必须是一个以空格分隔的标志,当xargs分析到含有flag这个标志的时候就停止。-p 当每次执行一个argument的时候询问一次用户。-n num 后面加次数,表示命令在执行的时候一次用的argument的个数,默认是用所有的。-t 表示先打印命令,然后再执行。-i 或者是-I,这得看linux支持了,将xargs的每项名称,一般是一行一行赋值给 {},可以用 {} 代替。-r no-run-if-empty 当xargs的输入为空的时候则停止xargs,不用再去执行了。-d delim 分隔符,默认的xargs分隔符是回车,argument的分隔符是空格,这里修改的是xargs的分隔符。注意:linux命令格式一般为命令 命令选项 参数上一个命令的输出就是下一个命令的参数 这句话结合命令语法 应该知道输出的内容在下一个命令的位置了吧。案例[root@zutuanxue ~]# find / -name zutuanxue |xargs gzip [root@zutuanxue ~]# cat 112345678910[root@zutuanxue ~]# xargs -a 1 1 2 3 4 5 6 7 8 9 10[root@zutuanxue ~]# xargs -a 1 -E 5 1 2 3 4这样就明白使用xargs -a 为什么读取文件的时候会把文件中的所有内容都输出了吧[root@zutuanxue ~]# xargs -a 1 -pecho 1 2 3 4 5 6 7 8 9 10 ?...y1 2 3 4 5 6 7 8 9 10[root@zutuanxue ~]# xargs -a 1 -pecho 1 2 3 4 5 6 7 8 9 10 ?...n同理为什么把文件中的所有行按一行输出呢,原因就是默认输出所有[root@zutuanxue ~]# xargs -a 1 -n31 2 34 5 67 8 910[root@zutuanxue ~]# xargs -a 1 -n3 -pecho 1 2 3 ?...yecho 4 5 6 ?...1 2 3yecho 7 8 9 ?...4 5 6yecho 10 ?...7 8 9y10和-p命令选项一样,显示他是怎么执行的,只不过这个不需要确认。[root@zutuanxue ~]# cat 1 |xargs -techo 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 6 7 8 9 10为何读入文件会把所有行都放在一行呢?这个和xargs的列分割符有关系默认是回车我们可以使用-d 改掉默认列与列的默认分割符为其他,自然就会换行了[root@zutuanxue ~]# xargs -a 1 -d \"@\"12345678910
9、shell字符
有基础的同学不要和正则表达式中的符号含义搞混淆了。 !: 执行历史命令 !! 执行上一条命令 $: 变量中取内容符 + - * / %: 对应数学运算 加 减 乘 除 取余数 &: 后台执行 ;: 分号可以在shell中一行执行多个命令,命令之间用分号分割 \\: 转义字符 ``: 反引号 命令中执行命令 echo \"today is `date +%F`\" \' \': 单引号,脚本中字符串要用单引号引起来,但是不同于双引号的是,单引号不解释变量 \" \": 双引号,脚本中出现的字符串可以用双引号引起来通配符 ~: 家目录 # cd ~ 代表进入用户家目录 *: 星号是shell中的通配符 匹配所有 ?: 问号是shell中的通配符 匹配除回车以外的一个字符 [list]: 匹配[list]中的任意单个字符[!list]: 匹配除list中的任意单个字符{string1,string2,...}: 匹配string1,string2或更多字符串重定向> 覆盖输入 >> 追加输入< 输出<< 追加输出管道命令|: 管道符 上一个命令的输出作为下一个命令的输入 cat filename | grep \"abc\"
10、组合命令实战
job1: 检索本机的IP、NETMASK、MAC地址、广播地址IP: 172.20.10.3NetMask: 255.255.255.240Broadcast: 172.20.10.15MAC Address: 00:0c:29:8d:49:eajob2: 将系统中所有普通用户的用户名、密码和默认shell保存到一个文件中,要求用户名密码和默认shell之间用tab键分割ayitula x /bin/bash组合命令实战代码job1: 检索本机的IP、NETMASK、MAC地址、广播地址[root@zutuanxue ~]# ifconfig ens33 检索网卡信息[root@zutuanxue ~]# ifconfig ens33|grep -w inet|tr -d \'[a-zA-Z]\'|tr -s \" \" 处理检索行IP地址[root@zutuanxue ~]# ifconfig ens33|grep -w inet|tr -d [a-zA-Z]|tr -s \" \"|cut -d \" \" -f2|xargs echo \"IP: \"IP: 172.20.10.3NetMask地址[root@zutuanxue ~]# ifconfig ens33|grep -w inet|tr -d [a-zA-Z]|tr -s \" \"|cut -d \" \" -f3|xargs echo \"NetMask: \"NetMask: 255.255.255.240广播地址[root@zutuanxue ~]# ifconfig ens33|grep -w inet|tr -d [a-zA-Z]|tr -s \" \"|cut -d \" \" -f4|xargs echo \"Broadcast: \"Broadcast: 172.20.10.15MAC地址[root@zutuanxue ~]# ifconfig ens33|grep -w ether|tr -s \" \"|cut -d \" \" -f3|xargs echo \"MAC Address: \"MAC Address: 00:0c:29:8d:49:eajob2: 将系统中所有普通用户的用户名、密码和默认shell保存到一个文件中,要求用户名密码和默认shell之间用tab键分割[root@zutuanxue ~]# cut -d \":\" -f1,2,7 /etc/passwd|tr \":\" \"\\t\"|grep -i \"bash\"|grep -v \"root\"ayitula x /bin/bash
1 . 磁 盘 使 用 率 检 测 ( 用 s h e l l 脚 本 )
#!/bin/bash# 使用 ip 命令更可靠地获取 IP(适配现代系统)IP=$(ip -4 addr show ens160 | awk \'/inet / {print $2}\' | cut -d \'/\' -f 1)# 仅提取物理磁盘分区(排除 tmpfs 等内存文件系统)的使用率SPACE=$(df -Ph | grep \'/dev/sd\' | awk \'{print int($5)}\')for i in $SPACEdo if [ $i -ge 90 ]; then echo \"$IP 的磁盘分区使用率已超 90%,请及时处理\" else echo \"磁盘健康\" fidone
五、bash shell基本特性
1、 命令和文件自动补全
Tab只能补全命令和文件
2、 常见的快捷键—提升操作熟练度
^c 终止前台运行的程序^z 将前台运行的程序挂起到后台^d 退出 等价exit^l 清屏 ^a |home 光标移到命令行的最前端^e |end 光标移到命令行的后端^u 删除光标前所有字符^k 删除光标后所有字符^r 搜索历史命令ctrl+对应字母
六、shell变量
一些数据需要临时存放在内存,以待后续使用时快速读出,于是有了变量的定义
变量:变量是编程中最常用的一种临时在内存中存取数据的一种方式。
变量格式: 变量名=值
在shell编程中的变量名和等号之间不能有空格。变量名命名规则: 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。 中间不能有空格,可以使用下划线(_)。 不能使用标点符号。 不能使用bash里的关键字(可用help命令查看保留关键字)。VAR1=1age=18 整形name=‘baism’ 字符串score=88.8 浮点注意:字符串要用单引号或双引号引起来建议变量名为大写,和命令区分变量赋值,此种方法设置为本地变量[root@zutuanxue ~]# name=\"baism\"[root@zutuanxue ~]# school=\'ayitula\'[root@zutuanxue ~]# age=30[root@zutuanxue ~]# score=88.8
1.变量存取原理
关于内存的说明a、系统启动 内存被按照1B一个单位划分成N块 并且以十六进制为每一个空间编号b、内存跟踪表记录 使用和未使用的内存的地址编号c、内存申请 系统从未使用的内存中拿出一个或者一段连续空间 给你使用 同时在内存跟踪表中记录该地址被占用不在分给别人,同时在系统中建立映射机制 比如:变量名 STRING1=‘ABC’name0x5d、释放内存从内存跟踪表中将记录删除,下次存数据直接覆盖
2.变量的内存分析图
1.当运行程序时,在内存中JVM会自动分配空间
2.内存中包含:
栈:存放方法以及方法中的局部变量
堆:存方法对象
方法区:代码片段、常量池、静态属性
常量池:常量池中存放的是字符串的值
结论:
基本数据类型的变量再内存中存放真正的值,比如:int、char、double
引用数据类型的变量在内存中存放地址,如:String
3.变量分类
系统中的变量根据作用域及生命周期可以分为四类:本地变量、环境变量、全局变量、内置变量
3.1、本地变量
用户自定义的变量,定义在脚本或者当前终端中,脚本执行完毕或终端结束变量失效。
3.2、环境变量
定义在用户家目录下的.bashrc或.bash_profile文件中,用户私有变量,只能本用户使用。
查看当前用户的环境变量 env
查询当前用户的所有变量(临时变量与环境变量) set
3.3、将当前变量变成环境变量 export
定义一个临时变量1、[root@zutuanxue tmp]# export A=hello //临时将一个本地变量(临时变量)变成环境变量[root@zutuanxue tmp]# env|grep ^AA=hello2、[root@zutuanxue tmp]# A=HELLO[root@zutuanxue tmp]# export A3、定义一个永久生效变量:vim .bash_profile 或者 ~/.bashrcA=hello关于export说明用户登录时:1) 用户登录到Linux系统后,系统将启动一个用户shell。在这个shell中,可以使用shell命令或声明变量,也可以创建并运行 shell脚本程序。运行脚本时:2) 运行shell脚本程序时,系统将创建一个子shell。此时,系统中将有两个shell,一个是登录时系统启动的shell,另一个是系统为运行脚本程序创建的shell。当一个脚本程序运行完毕,它的脚本shell将终止,可以返回到执行该脚本之前的shell。从这种意义上来说,用户可以有许多 shell,每个shell都是由某个shell(称为父shell)派生的。在子shell中定义的变量只在该子shell内有效。如果在一个shell脚本程序中定义了一个变量,当该脚本程序运行时,这个定义的变量只是该脚本程序内的一个局部变量,其他的shell不能引用它,要使某个变量的值可以在其他shell中被改变,可以使用export命令对已定义的变量进行输出。 export命令将使系统在创建每一个新的shell时定义这个变量的一个拷贝。这个过程称之为变量输出。
3.4、全局变量
使用export命令将本地变量输出为当前shell中的环境变量
所有用户及shell都可以使用,可以在/etc/profile /etc/bashrc下永久定义
打印全局变量 printenv定义格式export SCHOOL=\'zutuanxue\'测试方法:通过不同用户登录测试是否能读取变量
3.5、内置变量
系统变量(内置bash中变量) : shell本身已经固定好了它的名字和作用.
$?:上一条命令执行后返回的状态,当返回状态值为0时表示执行正常,非0值表示执行异常或出错 若退出状态值为0,表示命令运行成功 若退出状态值为127,表示command not found 若退出状态值为126,表示找到了该命令但无法执行(权限不够) 若退出状态值为1&2,表示没有那个文件或目录 $$:当前所在进程的进程号 echo $$ eg:kill -9 `echo $$` = exit 退出当前会话$!:后台运行的最后一个进程号 (当前终端) # gedit &!$ 调用最后一条命令历史中的参数!! 调用最后一条命令历史$#:脚本后面接的参数的个数$*:脚本后面所有参数,参数当成一个整体输出,每一个变量参数之间以空格隔开$@: 脚本后面所有参数,参数是独立的,也是全部输出$0:当前执行的进程/程序名 echo $0 $1~$9 位置参数变量${10}~${n} 扩展位置参数变量 第10个位置变量必须用{}大括号括起来./1.sh a b c[root@zutuanxue shell01]# cat 2.sh #!/bin/bash#xxxxecho \"\\$0 = $0\"echo \"\\$# = $#\"echo \"\\$* = $*\"echo \"\\$@ = $@\"echo \"\\$1 = $1\" echo \"\\$2 = $2\" echo \"\\$3 = $3\" echo \"\\$11 = ${11}\" echo \"\\$12 = ${12}\" 了解$*和$@的区别:$* :表示将变量看成一个整体$@ :表示变量是独立的#!/bin/bashfor i in \"$@\"doecho $idoneecho \"======我是分割线=======\"for i in \"$*\"doecho $idone[root@zutuanxue shell01]# bash 3.sh a b cabc======我是分割线=======a b c
变量总结说明:
本地变量:当前用户自定义的变量。当前进程中有效,其他进程及当前进程的子进程无效。
环境变量:当前进程有效,并且能够被子进程调用。
全局变量:全局所有的用户和程序都能调用,且继承,新建的用户也默认能调用.
内置变量:shell本身已经固定好了它的名字和作用.
3.6、变量取值
读取变量内容符: 读取方法:变量名
变量内容读出[root@zutuanxue ~]# echo $namelilee变量读取过程中,默认单引号是不解释变量的.比如[root@zutuanxue ~]# echo \'$name\'$name如果必须使用单引号还要读取变量的值可以使用eval命令[重新运算求出参数的内容] [root@zutuanxue ~]# eval echo \'$name\'baism
3.7.其他变量
url=www.taobao.com
)${#变量名}
echo ${#url}
15
(www.taobao.com
共 15 个字符)${变量名#*.}
*.
的部分echo ${url#*.}
taobao.com
(删除 www.
)${变量名##*.}
*.
的部分echo ${url##*.}
com
(删除 www.taobao.
)${变量名%.*}
.*
的部分echo ${url%.*}
www.taobao
(删除 .com
)${变量名%%.*}
.*
的部分echo ${url%%.*}
www
(删除 .taobao.com
)url=www.taobao.com
)${变量名/旧字符串/新字符串}
echo ${url/taobao/jd}
www.jd.com
${变量名//旧字符串/新字符串}
echo ${url//./-}
www-taobao-com
${变量名/#旧字符串/新字符串}
echo ${url/#www/WWW}
WWW.taobao.com
${变量名/%旧字符串/新字符串}
echo ${url/%com/COM}
www.taobao.COM
七、shell脚本格式化输出
计算机程序其实就是三步:输入、运算、输出,这个理论也适应于shell编程。
我们在使用shell写一个程序的时候,如果想让广大的用户都能使用,都能快速上手,那么好的交互界面就太重要了。我们可以使用多种方法开发好的、易交互的界面,常用的工具有:dialog、echo、printf等命令。
1、echo命令
功能:将内容输出到默认显示设备
语法:echo [-ne][字符串]补充说明:1、echo会将输入的字符串送往标准输出。2、输出的字符串间以空白字符隔开,并在最后加上换行号。OPTIONS:-n不要在最后自动换行-e若字符串中出现以下字符,则特别加以处理,而不会将它当成一般文字输出:转义字符\\a发出警告声;\\b删除前一个字符;\\t插入tab;\\n换行且光标移至行首;\\c最后不加上换行符号;\\f换行但光标仍旧停留在原来的位置;\\r光标移至行首,但不换行;\\v与\\f相同;\\插入\\字符;\\0nnn打印nnn(八进制)所代表的ASCII字符; 备注:数字0 不要理解成字母o\\xNN 打印NN(十六进制)所代表的ASCII字符;-–help显示帮助-–version显示版本信息你的进制转换过关吗?[root@zutuanxue ~]# echo -e \"\\0123\" #ot(123) = 83 对应ascii表的SS[root@zutuanxue ~]# echo -e \"\\x61\" #ox(61) = 97 对应ascii表的aa
2、输出颜色字体
脚本中echo显示内容带颜色显示,echo显示带颜色,需要使用参数-e
格式如下:echo -e \"\\033[字背景颜色;文字颜色m字符串\\033[0m\"例如: echo -e “\\033[41;36m something here \\033[0m”其中41的位置代表底色, 36m的位置是代表字的颜色1、字背景颜色和文字颜色之间是英文的2、文字颜色后面有个m3、字符串前后可以没有空格,如果有的话,输出也是同样有空格最后面控制选项说明 \\033[0m 关闭所有属性 \\033[1m 设置高亮度 \\033[4m 下划线 \\033[5m 闪烁 \\033[7m 反显 \\033[8m 消隐 \\033[30m — \\33[37m 设置前景色 \\033[40m — \\33[47m 设置背景色 \\033[nA 光标上移n行 \\033[nB 光标下移n行 \\033[nC 光标右移n行 \\033[nD 光标左移n行 \\033[y;xH设置光标位置 \\033[2J 清屏 \\033[K 清除从光标到行尾的内容 \\33[s 保存光标位置 \\033[u 恢复光标位置 \\033[?25l 隐藏光标 \\033[?25h 显示光标[root@zutuanxue ~]# echo -e \"\\033[0m today is fine \\033[3B\" today is fine
3、jobs
需求:输出一个水果购物界面 fruits_shop.sh
案例要点:
- echo输出缩进问题
- 字体颜色输出
job代码 01_fruits_shop.sh#!/bin/bash# #Author: www.zutuanxue.com#Release: #Description:打印水果超市列表echo -e \"\\t\\t \\033[32m Fruits List \\033[0m \\n\"echo -e \"\\t \\033[31mFruit\\033[0m \\t\\t \\033[31mPrice\\033[0m \\t\\t\\033[31mWeight\\033[0m\"echo -e \"\\t\\033[34m1)Apple\\t\\t¥10.00\\t\\t1KG\\033[0m\"echo -e \"\\t\\033[34m2)Banana\\t¥9.00\\t\\t1KG\\033[0m\"echo -e \"\\t\\033[34m3)Orange\\t¥15.20\\t\\t1KG\\033[0m\"
八、shell运算
计算机编程就是三大步:输入、运算、输出
1.赋值运算
赋值运算符 =
a=10 name=\'baism\' 重点:字符串必须用引号引起来
2.算数运算
四则运算符: + - * \\ 【加减乘除】
扩展: % ** 【取余 开方】
运算命令:
整形运算
– expr
– let
– $(())
– bc
浮点运算
– bc
expr 命令:只能做整数运算,格式比较古板,注意空格
let命令:只能做整数运算,且运算元素必须是变量,无法直接对整数做运算
双小圆括号运算,在shell中(( ))也可以用来做数学运算
浮点运算是采用的命令组合的方式来实现的 echo “scale=N;表达式”|bc
[root@zutuanxue ~]# expr 5 - 23[root@zutuanxue ~]# expr 5 \\* 2 #注意*出现应该转义,否则认为是通配符10——————[root@zutuanxue ~]# a=100[root@zutuanxue ~]# let a++;echo $a101[root@zutuanxue ~]# let a--;echo $a100[root@zutuanxue ~]# let a-=3;echo $a97[root@zutuanxue ~]# let a+=5;echo $a102————[root@zutuanxue ~]# echo $(( 100/3))33[root@zutuanxue ~]# echo $(( 100**3)) #开方运算1000000——————[root@zutuanxue ~]# echo \"scale=2;100/3\"|bc33.33echo \"scale=2;100*3\"|bc300
九、shell数组
有这样一个现实问题:一个班级学员信息系统,要求存储学员ID、NAME、SCORE、AGE、GENDER,班级有50个人,思考如何解决交互中数据存储的问题。使用数组来定义,只需要定义5个数组来接收所有用户的数据就可以了,5个数组就能解决一切
1、数组定义
普通数组:只能使用整数作为数组索引(元素的索引)
关联数组:可以使用字符串作为数组索引(元素的索引)
数组名称=(元素1 元素2 元素3 ...)
2、数组赋值方式
一次附一个值
变量名=变量值
array[0]=v1
一次附多个值
array=(var1 var2 var3 var4)
array1=(`cat /etc/passwd`) //将文件中每一行赋值给array1数组
数组取值
取值方式: ${数组名称[索引]}
索引: 默认情况下索引是指数组中的元素[存的值]在数组中的顺序,从0开始计数,关联数组除外。比如:
array=(var1 var2 var3 var4)
array数组中存有4个元素,分别是:var1 var2 var3 var4
那么我想取出var2这个元素,那么就得先看看他在数组中的位置,数组中的元素索引如下:
元素 var1 var2 var3 var4
索引 0 1 2 3
所以正确表示array数组中元素var2的方式是:${array[1]}
数组取值练习${array[i]} i表示元素的索引使用@ 或 * 可以获取数组中的所有元素:获取第一个元素echo ${array[0]}echo ${array[*]}获取数组里的所有元素echo ${#array[*]}获取数组里所有元素个数echo ${!array[@]} 获取数组元素的索引索引echo ${array[@]:1:2} 访问指定的元素;1代表从索引为1的元素开始获取;2代表获取后面几个元素
3、关联数组
关联数组使用首先需要申明该数组为关联数组,申明方式: declare -A 数组名称
首先声明关联数组declare -A asso_array1declare -A asso_array2declare -A asso_array3一次赋一个值数组名[索引]=变量值[root@zutuanxue ~]# asso_array1[linux]=one[root@zutuanxue ~]# asso_array1[java]=two一次附多个值[root@zutuanxue ~]# asso_array2=([name1]=harry [name2]=jack [name3]=amy [name4]=\"Miss zhang\")查看关联数组[root@zutuanxue ~]# declare -A[root@zutuanxue ~]# echo ${asso_array1[linux]}one[root@zutuanxue ~]# echo ${asso_array1[php]}three[root@zutuanxue ~]# echo ${!asso_array2[*]}name3 name2 name1 name4
十、shell函数
shell中允许将一组命令集合或语句形成一段可用代码,这些代码块称为shell函数。
将完成一个功能的一段代码进行命名、封装
函数的优点:
- 代码模块化,调用方便,节省内存
- 代码模块化,代码量少,排错简单
- 代码模块化,可以改变代码的执行顺序
函数定义
语法一:函数名 () { 代码块 return N }语法二:function 函数名 { 代码块 return N } 函数中return说明:1.return可以结束一个函数,类似于前面讲的循环控制语句break(结束当前循环,执行循环体后面的代码)2.return默认返回函数中最后一个命令的退出状态,也可以给定参数值,该参数值的范围是0-256之间。3.如果没有return命令,函数将返回最后一个Shell的退出值。
函数调用
[root@zutuanxue shell04]# cat fun1.sh #!/bin/bashhello(){echo \"hello zutuanxue $1\"hostname}menu(){cat <<-EOF1. mysql2. web3. app4. exitEOF}[root@zutuanxue shell04]# source fun1.sh [root@zutuanxue shell04]# . fun1.sh [root@zutuanxue shell04]# menu1. mysql2. web3. app4. exit
定义到用户的环境变量中
/etc/profile/etc/bashrc~/.bash_profile~/.bashrc[root@zutuanxue shell04]# cat ~/.bashrc # .bashrc# User specific aliases and functionsalias rm=\'rm -i\'alias cp=\'cp -i\'alias mv=\'mv -i\'# Source global definitionsif [ -f /etc/bashrc ]; then. /etc/bashrcfihello(){echo \"hello zutuanxue $1\"hostname}menu(){cat <<-EOF1. mysql2. web3. app4. exitEOF}注意:当用户打开bash的时候会读取该文件
十一、shell流程控制
1.if判断语句
假如 条件1 为真 那么 执行代码块1假如 条件2 为真 那么 执行代码块2 以此类推的N个条件及对应的执行代码块否则 【以上所有条件中没有一个满足的】 执行代码块X结束#!/bin/bash#Author: #Created Time: #Script Description: if [ $1 -ne $2 ] then if [ $1 -gt $2 ] thenecho \" $1 > $2 \" elseecho \" $1 < $2 \" fielse echo \" $1 = $2 \"fi
2.与文件存在与否的判断
-e是否存在 不管是文件还是目录,只要存在,条件就成立-f是否为普通文件-d是否为目录-Ssocket-ppipe-ccharacter-bblock-L软link
文件权限相关的判断
-r当前用户对其是否可读-w当前用户对其是否可写-x当前用户对其是否可执行-u是否有suid-g是否sgid-k是否有t位
两个文件的比较判断
两个文件的比较判断file1 -nt file2比较file1是否比file2新file1 -ot file2 比较file1是否比file2旧file1 -ef file2比较是否为同一个文件,或者用于判断硬连接,是否指向同一个inode整数之间的判断-eq相等-ne不等-gt大于-lt小于-ge 大于等于-le小于等于字符串之间的判断-z 是否为空字符串 字符串长度为0,就成立-n 是否为非空字符串 只要字符串非空,就是成立string1 == string2 是否相等string1 != string2 不等多重条件判断逻辑判断符号:&& (and 逻辑与) 两个条件同时满足,整个大条件为真||(or 逻辑或)两个条件满足任意一个,整个大条件为真! 非运算
简写if
省去了关键字,条件为真采用&&符号链接命令块,条件为假采用||链接命令块
简写if一般用在简单的判断中
if [ ! -d /tmp/baism ] then mkdir /tmp/baismfi可以简写为[ ! -d /tmp/baism ] && mkdir /tmp/baismif [ $USER == \'root\' ] then echo \"hello root\"else echo \"hello guest\"fi可以简写[ $USER == \'root\' ]&&echo \"hello root\" || echo \"hello guest\"
3.循环语句for
列表for循环:用于将一组命令执行已知的次数,下面给出了for循环语句的基本格式:
1.赋值来自一个范围for variable_name in {list} do command command … done2.或者直接赋值for variable in a b c do command command done3.for ((i=1;i<=5;i++));do echo $i;donefor ((i=1;i<=10;i+=2));do echo $i;donefor ((i=2;i<=10;i+=2));do echo $i;done4.for嵌套for打印99乘法表#!/bin/bash# #Author: www.zutuanxue.com#Created Time: #Release: #Description: #打印99乘法表,思考A*B的关系for ((A=1;A<=9;A++)) do for ((B=1;B<=$A;B++)) do echo -n -e \"$B*$A=$((A*B)) \\t\" done #换行 echo done5.for循环与数组使用for循环遍历读出数组name=(\'tom\' \'jarry\' \'harry\' \'barry\')for i in 0 1 2 3 do echo ${name[$i]} done使用for循环进行数组存值for i in `seq 0 9` do read -p \"name: \" name[$i] done
4.break语句
作用: 终止循环,执行循环体后面的代码
要求输出:1234执行完毕#!/bin/bash#Author: www.zutuanxue.com#Created Time: #Script Description: for i in `seq 1 9` do echo $i if [ $i -eq 5 ] then breakfidoneecho \"执行完毕\"
5.continue语句
作用: 跳过某次循环,继续执行下一次循环;表示循环体内下面的代码不执行,重新开始下一次循环
循环打印输出数字1到9,当执行输出到5时终止循环。#!/bin/bash#Author: www.zutuanxue.com#Created Time: #Script Description: for ((i=1;i<10;i++)) do if [ $i -eq 5 ] then continueelseecho $ifidoneecho \"执行完毕\"
6.sleep语句
作用: 控制循环的节奏,控制循环频率
当执行一个无限循环语句的时候,如果任意其循环那么该循环就会疯狂的消耗计算机的内存和CPU资源,消耗最大的就是CPU,所以一个循环不可能让其肆意循环,必须控制其循环的节奏,可以使用sleep语句来完成。
写一个倒计时程序:从9到1,每秒倒数一次。#!/bin/bash#Author: #Created Time: #Script Description: echo -n \"倒计时: \"for i in `seq 9 -1 1` do echo -n -e \"\\b$i\" sleep 1doneecho echo \"执行完毕\"
7.脚本退出命令-exit
作用: 退出程序并释放占用的系统资源
循环输出数字1-9,当循环到5时退出脚本。#!/bin/bash#Author: www.zutuanxue.com#Created Time: #Script Description: for i in `seq 1 9` do echo $i if [ $i -eq 5 ] then exit 0 fidoneecho \"执行完毕\"
8.while语句
特点:条件为真就进入循环;条件为假就退出循环,一般应用在未知循环次数的环境。
while [ 表达式 ]docommand...donewhile [ 1 -eq 1 ] 或者 (( 1 > 2 )) do command command ... done打印数组1-5num=1while [ $num -le 5 ] do echo $num let num++done
9.until语句
特点:条件为假就进入循环;条件为真就退出循环
until expression [ 1 -eq 1 ] (( 1 >= 1 ))docommandcommand...done使用while循环和until循环打印数字接龙,要求while循环输出1-5,until循环输出6-9.#!/bin/bash# #Author: www.zutuanxue.com#Created Time: #Release: #Description: 数字接龙i=1while [ $i -le 5 ]doecho $ilet i++until [ $i -le 5 ]do echo $i let i++ [ $i -eq 10 ]&&breakdonedone
10.case语句
特点:根据给予的不同条件执行不同的代码块
case $var in 定义变量;var代表是变量名pattern 1) 模式1;用 | 分割多个模式,相当于or command1 需要执行的语句 ;; 两个分号代表命令结束pattern 2) command2 ;;pattern 3) command3 ;; *) default,不满足以上模式,默认执行*)下面的语句 command4 ;;esacesac表示case语句结束
11、正则表达式
正则表达式(Regular Expression、regex或regexp,缩写为RE),也译为正规表示法、常规表示法,是一种字符模式,用于在查找过程中匹配指定的字符。
定位符使用技巧:同时锚定开头和结尾,做精确匹配;单一锚定开头或结尾或者不锚定的,做模糊匹配。
匹配符:匹配字符串
限定符:对前面的字符或者(字符串)出现的次数做限定说明
posix字符一次只匹配一个范围中的一个字节
以a开头c结尾的字符串[root@zutuanxue ~]# egrep \"^ac$\" file ac以a开头[root@zutuanxue ~]# egrep \"^a\" file ac以a开头c结尾 中间任意 长度为三个字节的字符串[root@zutuanxue ~]# egrep \"^a.c$\" file acc以cc结尾的字符串 因为$只能锚定单个字符,如果是一个字符串就需要用()来做定义[root@zutuanxue ~]# egrep \"(cc)$\" file abcc以a开头c结尾 中间是a-z,0-9 长度为三个字节的字符串[root@zutuanxue ~]# egrep \"^a[a-z0-9]c$\" file acc以a开头 c结尾 中间是有b或者没有b 长度不限的字符串[root@zutuanxue ~]# egrep \"^ab*c$\" file 以a开头 c结尾 中间只出现一次b或者没有b的字符串[root@zutuanxue ~]# egrep \"^ab?c$\" file 以a开头 c结尾 中间是有b且至少出现一次 长度不限的字符串[root@zutuanxue ~]# egrep \"^ab+c$\" file 以a开头 c结尾 中间是有b且至少出现两次最多出现四次 长度不限的字符串[root@zutuanxue ~]# egrep \"^ab{2,4}c$\" file 以a开头 c结尾 中间是有b且正好出现三次的字符串[root@zutuanxue ~]# egrep \"^ab{3}c$\" file abbbc以a开头 c结尾 中间是有b且至少出现一次的字符串[root@zutuanxue ~]# egrep \"^ab{1,}c$\" file abbc注意[[ ]] 双中括号的意思: 第一个中括号是匹配符[] 匹配中括号中的任意一个字符,第二个[]是格式 如[:digit:]1)精确匹配 以a开头c结尾 中间a-zA-Z0-9任意字符 长度为三个字节的字符串[root@zutuanxue ~]# egrep \"^a[[:alnum:]]c$\" fileaccabcaZca3c2)精确匹配 以a开头c结尾 中间是a-zA-Z任意字符 长度为三个字节的字符串[root@zutuanxue ~]# egrep \"^a[[:alpha:]]c$\" fileaccabcaZc3)精确匹配 以a开头c结尾 中间是0-9任意字符 长度为三个字节的字符串[root@zutuanxue ~]# egrep \"^a[[:digit:]]c$\" filea3c4)精确匹配 以a开头c结尾 中间是a-z任意字符 长度为三个字节的字符串[root@zutuanxue ~]# egrep \"^a[[:lower:]]c$\" fileaccabc4)精确匹配 以a开头c结尾 中间是A-Z任意字符 长度为三个字节的字符串[root@zutuanxue ~]# egrep \"^a[[:upper:]]c$\" fileaZc5)精确匹配 以a开头c结尾 中间是非空任意字符 长度为三个字节的字符串[root@zutuanxue ~]# egrep \"^a[[:print:]]c$\" fileaccabca_caZca ca3c6)精确匹配 以a开头c结尾 中间是符号字符 长度为三个字节的字符串[root@zutuanxue ~]# egrep \"^a[[:punct:]]c$\" filea_c7)精确匹配 以a开头c结尾 中间是空格或者TAB符字符 长度为三个字节的字符串[root@zutuanxue ~]# egrep \"^a[[:blank:]]c$\" filea c类似[root@zutuanxue ~]# egrep \"^a[[:space:]]c$\" filea c8)精确匹配 以a开头c结尾 中间是十六进制字符 长度为三个字节的字符串[root@zutuanxue ~]# egrep \"^a[[:xdigit:]]c$\" fileaccabca3c
12.sed
sed是linux中提供的一个外部命令,它是一个行(流)编辑器,非交互式的对文件内容进行增删改查的操作,使用者只能在命令行输入编辑命令、指定文件名,然后在屏幕上查看输出。它和文本编辑器有本质的区别。
区别是: 文本编辑器: 编辑对象是文件 行编辑器:编辑对象是文件中的行
sed [options] ‘{command}[flags]’ [filename]
#命令选项-e script 将脚本中指定的命令添加到处理输入时执行的命令中 多条件,一行中要有多个操作-f script 将文件中指定的命令添加到处理输入时执行的命令中-n 抑制自动输出-i 编辑文件内容-i.bak 修改时同时创建.bak备份文件。-r 使用扩展的正则表达式! 取反 (跟在模式条件后与shell有所区别)#command 对文件干什么sed常用内部命令a 在匹配后面添加i 在匹配前面添加d 删除s 查找替换 字符串c 更改y 转换 N D P p 打印#flags数字 表示新文本替换的模式g: 表示用新文本替换现有文本的全部实例p: 表示打印原始的内容w filename: 将替换的结果写入文件
文件内容增加操作,将数据追加到某个位置之后,使用命令a。
文件内容增加操作,将数据插入到某个位置之前,使用命令i。
文件内容修改操作–替换,将一行中匹配的内容替换为新的数据,使用命令s。
文件内容修改操作–更改,将一行中匹配的内容替换为新的数据,使用命令c。
文件内容修改操作–字符转换,将一行中匹配的内容替换为新的数据,使用命令y。
文件内容删除,将文件中的指定数据删除,使用命令d。
文件内容查看,将文件内容输出到屏幕,使用命令p。
在命令行中使用多个命令 -e
1.在第二到四行每行后新开一行追加数据: append data \"haha\"[root@zutuanxue ~]# sed \'2,4a\\append data \"haha\"\' data11 the quick brown fox jumps over the lazy dog.2 the quick brown fox jumps over the lazy dog.append data \"haha\"3 the quick brown fox jumps over the lazy dog.append data \"haha\"4 the quick brown fox jumps over the lazy dog.append data \"haha\"5 the quick brown fox jumps over the lazy dog.匹配字符串追加: 找到包含\"3 the\"的行,在其后新开一行追加内容: append data \"haha\"[root@zutuanxue ~]# sed \'/3 the/a\\append data \"haha\"\' data11 the quick brown fox jumps over the lazy dog.2 the quick brown fox jumps over the lazy dog.3 the quick brown fox jumps over the lazy dog.append data \"haha\"4 the quick brown fox jumps over the lazy dog.5 the quick brown fox jumps over the lazy dog.//开启匹配模式 /要匹配的字符串/2.在第二行前新开一行插入数据: insert data \"haha\"[root@zutuanxue ~]# sed \'2i\\insert data \"haha\"\' data11 the quick brown fox jumps over the lazy dog.insert data \"haha\"2 the quick brown fox jumps over the lazy dog.匹配字符串插入: 找到包含\"3 the\"的行,在其前新开一行插入内容: insert data \"haha\"[root@zutuanxue ~]# sed \'/3 the/i\\insert data \"haha\"\' data1执行替换命令并修改文件[root@zutuanxue ~]# sed -i.bak \'s/brown/green/\' data13.[root@zutuanxue ~]# echo \"this is a test\" |sed \'s/test/text/\'this is a text将data1中第二到第四行的dog替换为cat[root@zutuanxue ~]# sed \'2,4s/dog/cat/\' data1匹配字符串替换:将包含字符串\"3 the\"的行中的dog替换为cat[root@zutuanxue ~]# sed \'/3 the/s/dog/cat/\' data14.将data1文件中包含\"3 the\"的行内容更改为: change data \"haha\"[root@zutuanxue ~]# sed \'/3 the/c\\change data \"data\"\' data1将data1文件中的第二、三、四行的内容更改为:change data \"haha\"[root@zutuanxue ~]# sed \'2,4c\\change data \"haha\"\' data15.将data1中的a b c字符转换为对应的 A B C字符[root@zutuanxue ~]# sed \'y/abc/ABC/\' data16.删除文件data1中的所有数据[root@zutuanxue ~]# sed \'d\' data1删除文件data1中的第三行数据[root@zutuanxue ~]# sed \'3d\' data17.打印data1文件第三行的内容[root@zutuanxue ~]# sed \'3p\' data1打印data1文件内容[root@zutuanxue ~]# sed \'p\' data18.将brown替换为green dog替换为cat[root@zutuanxue ~]# sed -e \'s/brown/green/;s/dog/cat/\' data11 the quick green fox jumps over the lazy cat.
从文件读取编辑器命令 -f 适用于日常重复执行的场景
1)将命令写入文件[root@zutuanxue ~]# vim abcs/brown/green/s/dog/cat/s/fox/elephant/2)使用-f命令选项调用命令文件[root@zutuanxue ~]# sed -f abc data1 1 the quick green elephant jumps over the lazy cat.2 the quick green elephant jumps over the lazy cat.3 the quick green elephant jumps over the lazy cat.4 the quick green elephant jumps over the lazy cat.5 the quick green elephant jumps over the lazy cat.
使用正则表达式 -r
打印data1中以字符串\"3 the\"开头的行内容[root@zutuanxue ~]# sed -n -r \'/^(3 the)/p\' data13 the quick brown fox jumps over the lazy dog.
标志
在sed命令中,标志是对sed中的内部命令做补充说明
1.数字标志:此标志是一个非零正数,默认情况下,执行替换的时候,如果一行中有多个符合的字符串,如果没有标志位定义,那么只会替换第一个字符串,其他的就被忽略掉了,为了能精确替换,可以使用数字位做定义。替换一行中的第二处dog为cat[root@zutuanxue ~]# sed \'s/dog/cat/2\' data22.g标志:将一行中的所有符合的字符串全部执行替换将data1文件中的所有dog替换为cat[root@zutuanxue ~]# sed \'s/dog/cat/g\' data23.p标志:打印文本内容,类似于-p命令选项[root@zutuanxue ~]# sed \'3s/dog/cat/p\' data24.w filename标志:将修改的内容存入filename文件中[root@zutuanxue ~]# sed \'3s/dog/cat/w text\' data2
十二、shell对输出流的处理-awk
过使用grep来过滤这些数据,使用cut、tr命令提出某些字段,但是他们都不具备提取并处理数据的能力,都必须先过滤,再提取转存到变量,然后在通过变量提取去处理,awk命令能够集过滤、提取、运算为一体。
awk是一种可以处理数据、产生格式化报表的语言,功能十分强大。awk 认为文件中的每一行是一条记录 记录与记录的分隔符为换行符,每一列是一个字段 字段与字段的分隔符默认是一个或多个空格或tab制表符。
awk的工作方式是读取数据,将每一行数据视为一条记录(record)每条记录以字段分隔符分成若干字段,然后输出各个字段的值。
awk的应用场景
字符串截取
数据运算
比如内存使用率脚本
awk [options] ‘[BEGIN]{program}[END]’ [FILENAME]
常用命令选项-F fs 指定描绘一行中数据字段的文件分隔符 默认为空格-f file 指定读取程序的文件名-v var=value 定义awk程序中使用的变量和默认值注意:awk 程序由左大括号和右大括号定义。 程序命令必须放置在两个大括号之间。由于awk命令行假定程序是单文本字符串,所以必须将程序包括在单引号内。1)程序必须放在大括号内2)程序必须要用单引号引起来awk程序运行优先级是: 1)BEGIN: 在开始处理数据流之前执行,可选项 2)program: 如何处理数据流,必选项 3)END: 处理完数据流后执行,可选项
awk基本应用
能够熟练使用awk对标准输出的行、列、字符串截取
awk对字段(列)的提取
字段提取:提取一个文本中的一列数据并打印输出
字段相关内置变量
$0 表示整行文本
$1 表示文本行中的第一个数据字段
$2 表示文本行中的第二个数据字段
$N 表示文本行中的第N个数据字段
$NF 表示文本行中的最后一个数据字段
读入test每行数据并把每行数据打印出来[root@zutuanxue ~]# awk \'{print $0}\' test 打印test第六个字段[root@zutuanxue ~]# awk \'{print $6}\' test打印test最后一个字段[root@zutuanxue ~]# awk \'{print $NF}\' test
命令选项详解
-F: 指定字段与字段的分隔符
当输出的数据流字段格式不是awk默认的字段格式时,我们可以使用-F命令选项来重新定义数据流字段分隔符。
-f file: 如果awk命令是日常重复工作,而又没有太多变化,可以将程序写入文件,每次使用-f调用程序文件就好,方便,高效。
-v 定义变量
1.处理的文件是/etc/passwd,希望打印第一列、第三列、最后一列[root@zutuanxue ~]# awk -F \':\' \'{print $1,$3,$NF}\' /etc/passwd2.[root@zutuanxue ~]# cat abc {print $1,$3,$NF}[root@zutuanxue ~]# awk -f abc test1 quick dog2 quick dog3 quick dog4 quick dog5 quick dog
awk对记录(行)的提取
记录提取:提取一个文本中的一行并打印输出
记录的提取方法有两种:a、通过行号 b、通过正则匹配
记录相关内置变量
NR: 指定行号 number row
提取test第三行数据指定行号为3[root@zutuanxue ~]# awk \'NR==3{print $0}\' test 3 the quick brown fox jumps over the lazy cat . dog指定行的第一个字段精确匹配字符串为3[root@zutuanxue ~]# awk \'$1==\"3\"{print $0}\' test 3 the quick brown fox jumps over the lazy cat . dog
awk对字符串提取
记录和字段的汇合点就是字符串
打印test第三行的第六个字段[root@zutuanxue ~]# awk \'NR==3{print $6}\' testjumps
awk程序的优先级
关于awk程序的执行优先级,BEGIN是优先级最高的代码块,是在执行PROGRAM之前执行的,不需要提供数据源,因为不涉及到任何数据的处理,也不依赖与PROGRAM代码块;PROGRAM是对数据流干什么,是必选代码块,也是默认代码块。所以在执行时必须提供数据源;END是处理完数据流后的操作,如果需要执行END代码块,就必须需要PROGRAM的支持,单个无法执行。
BEGIN:处理数据源之前干什么 不需要数据源就可以执行
PROGRAM: 对数据源干什么 【默认必须有】 需要数据源
END:处理完数据源后干什么 需要program 需要数据源
awk \'BEGIN { print \"hello zutuanxue\" } # 处理文件前执行一次{ print $0 } # 对每一行执行(默认打印整行)END { print \"bye zutuanxue\" } # 处理完所有行后执行一次\' test # 输入文件为 test$0 表示当前行的全部内容不需要数据源,可以直接执行[root@zutuanxue ~]# awk \'BEGIN{print \"hello world\"}\'hello world没有提供数据流,所以无法执行成功[root@zutuanxue ~]# awk \'{print \"hello world\"}\'[root@zutuanxue ~]# awk \'END{print \"hello world\"}\'
awk高级应用
awk定义变量和数组1.定义变量[root@zutuanxue ~]# awk -v name=\'baism\' \'BEGIN{print name}\'baism[root@zutuanxue ~]# awk \'BEGIN{name=\"baism\";print name}\'baism2.数组定义方式: 数组名[索引]=值定义数组array,有两个元素,分别是100,200,打印数组元素。[root@zutuanxue ~]# awk \'BEGIN{array[0]=100;array[1]=200;print array[0],array[1]}\'100 2003.awk运算赋值运算 =比较运算 > >= == < = 1 }\'1[root@zutuanxue ~]# awk \'BEGIN{print 100 == 1 }\'0c.数学运算[root@zutuanxue ~]# awk \'BEGIN{print 100+3 }\'103与运算:真真为真,真假为假,假假为假[root@zutuanxue ~]# awk \'BEGIN{print 100>=2 && 100>=3 }\'1[root@zutuanxue ~]# awk \'BEGIN{print 100>=2 && 1>=100 }\'0或运算:真真为真,真假为真,假假为假[root@zutuanxue ~]# awk \'BEGIN{print 100>=2 || 1>=100 }\'1[root@zutuanxue ~]# awk \'BEGIN{print 100>=200 || 1>=100 }\'0非运算[root@manage01 resource]# awk \'BEGIN{print ! (100>=2)}\'0e.匹配运算[root@zutuanxue ~]# awk -F \':\' \'$1 ~ \"^ro\" {print $0}\' /etc/passwdroot:x:0:0:root:/root:/bin/bash[root@zutuanxue ~]# awk -F \':\' \'$1 !~ \"^ro\" {print $0}\' /etc/passwd不匹配上述的条件的
awk 环境变量
FIELDWIDTHS:重定义列宽并打印,注意不可以使用$0打印所有,因为$0是打印本行全内容,不会打印你定义的字段[root@zutuanxue ~]# awk \'BEGIN{FIELDWIDTHS=\"5 2 8\"}NR==1{print $1,$2,$3}\' /etc/passwdroot: x: 0:0:rootFS:指定数据源中字段分隔符,类似命令选项-F[root@zutuanxue ~]# awk \'BEGIN{FS=\":\"}NR==1{print $1,$3,$NF}\' /etc/passwdroot 0 /bin/bashOFS:指定输出到屏幕后字段的分隔符[root@zutuanxue ~]# awk \'BEGIN{FS=\":\";OFS=\"-\"}NR==1{print $1,$3,$NF}\' /etc/passwdroot-0-/bin/bashRS:指定记录的分隔符[root@zutuanxue ~]# awk \'BEGIN{RS=\"\"}{print $1,$13,$25,$37,$49}\' test1 2 3 4 5将记录的分隔符修改为空行后,所有的行会变成一行,所以所有字段就在一行了。ORS:输出到屏幕后记录的分隔符,默认为回车[root@zutuanxue ~]# awk \'BEGIN{RS=\"\";ORS=\"*\"}{print $1,$13,$25,$37,$49}\' test1 2 3 4 5*[root@zutuanxue ~]# 可以看出,提示符和输出在一行了,因为默认回车换成了*
流程控制
单if语句打印$1大于5的行[root@zutuanxue ~]# awk \'{if($1>5)print $0}\' numif...else语句假如$1大于5则除以2输出,否则乘以2输出[root@zutuanxue ~]# awk \'{if($1>5)print $1/2;else print $1*2}\' numfor循环语句[root@zutuanxue ~]# cat num260 50 100150 30 1070 100 40将文件中的每行的数值累加,和大于或等于150就停止累加[root@zutuanxue ~]# awk \'{sum=0;i=1;do{sum+=$i;i++}while(sum<150);print sum}\' num2将一行中的数据都加起来 $1+$2+$3[root@zutuanxue ~]# awk \'{sum=0;for (i=1;i<4;i++){sum+=$i}print sum}\' num2while循环语句–先判断后执行[root@zutuanxue ~]# awk \'{sum=0;i=1;while(sum<150){sum+=$i;i++}print sum}\' num2210do…while循环语句–先执行后判断[root@zutuanxue ~]# awk \'{sum=0;i=1;do{sum+=$i;i++}while(sum sum=0> i=1> while (i sum+=$i> if (sum>150){> break> }> i++> }> print sum> }\' num2