1 shell介绍
-
什么是shell
shell是一个程序,采用c语言编写,是用户和linux内核沟通的桥梁,它既是一种命令语句,又是一种解释性的编程语言
kernel <----> shell <----> user
- kernel:为软件服务,接收用户或软件指令驱动硬件,完成工作
- shell :命令解释器
- user:用户接口,对接用户
-
shell的功能
- 命令行解释功能
- 启动程序
- 输入输出重定向
- 管道连接
- 文件名置换(echo /*)
- 变量维护
- 环境控制
- shell编程
2 shell语法
shell脚本就是,将完成一个任务的所有的命令,按照执行的先后顺序,自上而下写入到一个文本文件,然后给予执行权限
-
如何书写一个shell脚本
-
shell脚本的命名
名字要有意义,建议用
.sh
结尾,且见名知意,如check_memory.sh
-
shell脚本格式
- shell脚本开头必须指定脚本运行环境,以
#!
这个特殊符号组合来组成
#!/bin/bash #指定该脚本是运行解析由/bin/bash来完成的
-
shell中的注释使用
#
号#定义脚本执行环境 #!/usr/bin/bash #shell脚本中,最好加入脚本说明字段 #! /usr/bin/bash #Author: xxx #Created Time: 2020/09/06 21:52 #Release:1.0 #Script Description: first shell study script #脚本组成 # 解释环境 #!/usr/bin/bash # 注释说明 # 执行代码
- shell脚本开头必须指定脚本运行环境,以
-
-
shell脚本运行
-
脚本运行需要执行权限,给一个文件赋予执行权限后,该脚本就可以运行
chmod 700 filename
-
如果不希望赋予脚本执行权限,可以使用
bash
命令来运行未给予执行权限的脚本bash filename
-
-
shell中的特殊符号
特殊符号 描述 ~ 家目录, # cd ~ 代表进入用户家目录
! 执行历史命令, !!执行上一条命令
$ 变量中取内容符 +、-、*、/、% 对应数学运算,加、减、乘、除、取余数 & 后台执行 * 星号是shell中的通配符 匹配所有 ? 问号是shell中的通配符 匹配除回车以外的一个字符 ; 分号可以在shell中一行执行多个命令,命令之间用分号分隔 | 管道符 上一个命令的输出作为下一个命令的输入 `cat filename 转义字符 `` 反引号,命令中执行命令 echo “today is date +%F
”‘ 单引号,脚本中字符串要用单引号引起来,但是不同于双引号的是,单引号不解释变量 “ 双引号,脚本中出现的字符串可以用双引号引起来 -
管道
| 管道符在shell中使用是最多的,很多组合命令都需要通过组合命令来完成输出 管道符其实就是上一个命令的输出作为下一个命令的输入
-
重定向
> 重定向输入 覆盖原数据 >> 重定向追加输入,在原数据的末尾添加 < 重定向输出 #wc -l < /etc/passwd >> 重定向追加输出 #fdisk /dev/sdb <<EOF ...... EOF
-
shell中数学运算
expr 命令:只能做整数运算,格式比较古板,注意空格 # expr 1 + 1 # expr 1 * 2 --注意*出现时应该转义,否则认为是通配符 --扩展 #echo 7 + 1 #echo $? --$?能够判断上一个命令执行是否成功,成功则返回0,否则返回其他数字 #expr 7 + 1.1 &>/dev/null ; echo $? --/dev/null 代表回收站 --复合命令 #echo "当前内存使用率:" `echo "scale=2;141*100/7988"|bc`%" 使用率" --双小圆括号运算,在shell中(()),也可以用来做数学运算 #echo $((100+3))
-
脚本退出
exit NUM 退出脚本,释放系统资源,NUM代表一个整数,代表返回值.
3 shell格式化输出
一个程序需要有0个或以上输入,一个或更多输出
-
echo命令介绍
-
**功能: **将内容输出到默认显示设备
echo命令的功能是在显示器上显示一段文字,一般起到一个提示的作用.
-
**语法: **
echo [-ne][字符串]
--补充说明 echo会将输入的字符串送往标准输出.输出的字符串间以空白字符隔开,并在最后加上换行号. --命令选项 -n 不要在最后自动换行 -e 若字符串中出现以下字符,则特别加以处理,而不会将它当成一般文字输出: 转义字符 a 发出警告声 删除前一个字符 c 最后不加上换行符号 f 换行但光标仍旧停留在原来的位置 换行且光标移至行首 光标移至行首,但不换行 插入tab v 与f相同 插入字符 nn插入nnn(八进制)所代表的ASCII字符 -help 显示帮助 -version 显示版本信息
#!/bin/bash for time in `seq 9 -1 0`;do echo -n -e "$time" sleep 1 done echo
-
4 shell基本输入
-
read命令
默认接受键盘的输入,回车符代表输入结束
--read命令选项 -p 打印信息 -t 限定时间 -s 不回显 -n 输入字符个数
#!/bin/bash clear echo -n -e "Login: " read login echo -n -e "Password: " read -t5 -s -n6 password echo "account: $login password: $password"
5 变量
-
变量介绍
计算机的单位: 1B=8bit 1KB=1024B 1MB=1024KB 1GB=1024MB 1TB=1024GB 1PB=1024TB 1EB=1024PB 1ZB=1024EB ...
- **定义: **变量是编程中最常用的一种临时在内存中存取数据的一种方式
-
变量分类
- 本地变量: 用户私有变量,只有本地用户可以使用,保存在家目录下的
.bash_profile、.bashrc
文件中 - 全局变量: 所有用户都可以使用,保存在
/etc/profile、/etc/bashrc
文件中 - 用户自定义变量: 用户自定义,比如脚本中的变量
- 本地变量: 用户私有变量,只有本地用户可以使用,保存在家目录下的
-
定义变量
-
变量格式:
变量名=值
在shell编程中的变量名和等号之间不能有空格
变量名命名规则: 1.命名只能使用英文字母,数字和下划线,首个字母不能以数字开头 2.中间不能有空格,可以使用下划线"_" 3.不能使用标点符号 4.不能使用bash里的关键字(可用help命令查看保留关键字) 注意: 1.字符串要用单引号或双引号引起来
-
-
读取变量内容
读取变量内容符 :
$
读取方法 :
$变量名
A="test_name" echo $A
-
取消变量 unset
#unset A
-
定义全局变量 export
#export name='test_name' 如果希望本地变量或者全局变量可以永久使用,可以将需要设置的变量写入变量文件中即可
-
定义永久变量
本地变量: 用户私有变量,只有本用户可以使用...
全局变量: 所有用户都可以使用...
6 数组
-
数组介绍
-
基本数组
数组可以让用户一次赋予多个值,需要读取数据时只需通过索引调用就可以方便读出.
-
数组语法
数组名称=(元素1 元素2 元素3 ...)
-
数组读出
${数组名称[索引]} 索引默认是元素在数组中的排队编号,默认第一个从0开始
-
数组赋值
-
方法1:一次赋一个值
array_0[0]='0'
-
方法2:一次赋多个值
#array_0=(tom jack alice) #array_0=(`cat /etc/passwd`) --希望是将该文件中的每一个行作为一个元素赋值给数组array_0 #array_0=(`ls /usr/bin`)
-
-
查看数组
#declare -a --查看当前bash定义的数组
-
访问数组元素
#echo ${array_0[0]} --访问数组中的第一个元素 #echo ${array_0[@]} --访问数组中所有元素,等同于 echo ${array_0[*]} #echo ${#array_0[@]} --统计数组元素的个数 #echo ${!array_0[@]} --获取数组元素的索引 #echo ${array_0[@]:1} --从数组下标1开始 #echo ${array_0[@]:1:2} --从数组下标1开始,访问两个元素
-
遍历数组
方法一:默认数组通过数组元素的个数进行遍历
方法二:针对关联数组可以通过数组元素的索引进行遍历
-
-
关联数组
关联数组可以允许用户自定义数组的索引,这样使用起来更加方便、高效.
-
定义关联数组
申明关联数组变量 #declare -A ass_array_1 #declare -A ass_array_2
-
关联数组赋值
方法一:一次赋一个值 数组名[索引]=变量名 #ass_array_1[index_name]=value_name 方法二:一次赋多个值 #ass_array_2=([index_name_1]=tom [index_name_2]=jack ...)
-
查看数组
# declare -A
-
7 shell流程控制-if判断语句
-
shell中的运算
-
数学比较运算
运算符解释: -eq 等于 -ge 大于或等于 -gt 大于 -le 小于或等于 -lt 小于 -ne 不等于 注意: 1.只能比较整型 2.遇到浮点型需要比较的,则可将其放大10倍
-
字符串比较运算
运行符解释,注意字符串别忘了使用引号引起来 == 等于 != 不等于 -n 检查字符串的长度是否大于0 -z 检查字符串的长度是否为0
-
文件比较与检查
test -d 检查文件是否存在且为目录 -e 检查文件是否存在 -f 检查文件是否存在且为文件 -r 检查文件是否存在且可读 -s 检查文件是否存在且不为空 -w 检查文件是否存在且可写 -x 检查文件是否存在且可执行 -O 检查文件是否存在且被当前用户拥有 -G 检查文件是否存在并且默认组为当前用户组 file1 -nt file2 检查file1是否比file2新 file1 -ot file2 检查file1是否比file2旧
-
逻辑运算
逻辑与运算 && 逻辑或运算 || 逻辑非运算 | 逻辑运算注意事项: 逻辑与 或 运算都需要两个或以上条件,逻辑非运算只能一个条件
-
赋值运算
= 赋值运算符
-
-
if语法
-
语法1: 单if语句
适用范围: 只需要一步判断,条件返回真干什么,或者返回假干什么
语句格式:
if [condition] #condition 值为true or false then commands fi
-
语法2: if-then-else
适用范围: 两步判断,条件为真干什么,条件为假干什么
if [condition] then commands1 else commands2 if
#!/bin/bash if [ $1 -eq $2] then echo "$1 = $2" else if [ $1 -gt $2] then echo "$1 > $2" else echo "$1 < $2" fi fi
-
语法3: if-then-elif语句
适用范围: 多于两个以上的判断结果,也就是多于一个以上的判断条件
if [condition 1] then commands1 elif [condition 2] then commands2 else commands3 if
#!/bin/bash if [ $1 -eq $2] then echo "$1 = $2" elif [ $1 -gt $2 ] then echo "$1 > $2" else echo "$1 < $2" fi
-
-
if高级应用
-
条件符号使用双圆括号,可以在条件中植入数学表达式
#!/bin/bash if (( 100%3+1>10 ));then echo "yes" else echo "no" fi
-
使用双方括号,可以在条件中使用通配符
#!/bin/bash for i in r1 rr2 cc rr3 do if [[ $i == r* ]];then echo $i fi done
-
8 shell流程控制-for循环语句
-
for循环介绍
-
for语法
-
for 语法一
for var in value1 value2 ...... do commands done
for i in `seq 1 9` do echo $i done
-
for语法二
C式的for命令 for ((变量;条件;自增减运算)) do 代码块 done
for ((i=1;i<10;i++)) do echo $i done
-
9 循环控制语句
-
sleep N 脚本执行到该步休眠N秒
-
continue跳过循环中的某次循环
#!/bin/bash for ((i=1;i<10;i++)) do if [ $i -eq 5 ];then continue fi echo $i done
-
**break跳出循环继续执行后续代码 **
10 shell流程控制-while循环语句
-
while循环介绍
知道循环次数就可以使用for,如果不知道代码要循环多少次,就使用while
-
while循环语法
while [ condition ] #注意,条件为真while才会循环,条件为假,while停止循环 do commands done
-
while循环实战
#!/bin/bash read -p "login: " account while [ $account != 'root' ] do read -p "login: " account done
11 until语句
-
until介绍
和while正好相反,until是条件为假开始执行,条件为真停止执行
-
until语法
until [ condition ] #注意,条件为假until才会循环,条件为真,until停止循环 do commands代码块 done
12 case多条件分支语句
-
case介绍
根据不同的状况来执行不同的预案
-
case语法
case 变量 in 条件1) 执行代码块1 ;; 条件2) 执行代码块2 ;; ... esac 注意:每个代码块执行完毕要以;;结尾代表结束,case结尾要以倒过来写的esac来结束
13 shell特殊变量
-
特殊参数
$0 脚本的名字 $* 代表所有参数,其间隔为IFS内定参数的第一个字元 $@ 与*星号类同,不同之处在于不参照IFS $# 代表参数数量 $ 执行上一个指令的返回值 $- 最近执行的foreground pipeline的选项参数 $$ 本身的Process ID $: 执行上一个背景的PID $_ 显示出最后一个执行的命令 $N shell的第几个外传参数
14 shell函数
-
函数介绍
将代码模块化,一个模块实现一个功能. 函数的优点: 1.代码模块化,调用方便,节省内存 2.代码模块化,代码量少,排错简单 3.代码模块化,可以改变代码的执行顺序
-
函数语法
语法一: 函数名 () { 代码块 return N }
语法二: function 函数名 { 代码块 return N }
-
函数应用
#定义一个函数 print_str () { echo "welcome to my home" } #或者 function hello { echo "hello world" } #调用 print_str hello --说明 1.print和hello就是函数的名字,函数名字命名参考变量命名规则 2.定义好函数后,如果想调用该函数,只需通过函数名调用即可
#!/bin/bash #变量区 proc=nginx nginx_install_doc="/usr/local/nginx" nginxd="$nginx_install_doc/sbin/nginx" pid_file="$nginx_install_doc/logs/nginx.pid" #系统提供的函数库 #if [ -f /etc/init.d/functions ];then # . /etc/init.d/functions #else # echo "not found file /etc/init.d/functions" # exit #fi #function start() { # 如果nginx没有启动,直接启动,否则报错,已经启动 if [ -f $pid_file ];then # 获取进程id nginx_process_id=`cat $pid_file` # 通过进程id查询相关进程状态,统计数量 nginx_process_num=`ps aux | grep $nginx_process_id | grep -v "grep" | wc -l` fi #如果文件存在且进程数量等于1,代表nginx在运行中 if [ -f $pid_file ]&&[ $nginx_process_num -ge 1 ];then echo " nginx running... " else #如果文件存在且进程数量小于1,代表nginx未运行 if [ -f $pid_file ]&&[ $nginx_process_num -lt 1 ];then #删除进程 rm -f $pid_file #启动进程 echo " nginx start `daemon $nginxd` " #另一种启动的方式 #action "nginx start" $nginxd fi echo " nginx start `daemon $nginxd` " fi } stop() { if [ -f $pid_file ]&&[ $nginx_process_num -ge 1];then action "nginx stop" killall -s QUIT $proc rm -f $pid_file else action "nginx stop" killall -s QUIT $proc 2>/dev/null fi } restart () { stop sleep 1 start } reload () { if [ -f $pid_file ]&&[ $nginx_process_num -ge 1 ];then action "nginx reload" killall -s HUP $proc else action "nginx reload" killall -s HUP $proc 2>/dev/null fi } status () { if [ -f $pid_file ]&&[ $nginx_process_num -ge 1 ];then echo "nginx running..." else echo "nginx stop" fi } #callable case $1 in start) start;; stop) stop;; restart) restart;; reload) reload;; status) status;; *) ehco "USAGE: $0 start|stop|restart|reload|status";; esac
15 正则表达式之特殊字符
-
正则表达式介绍
正则表达式是一种文本模式匹配,包括普通字符(例如,a到z之间的字母)和特殊字符(称为“元字符”).它是一种字符串匹配的模式,可以用来检查一个字符串是否含有某种子串、将匹配的子串替换或者从某个字符串中取出某个条件的子串.
shell支持正则表达式,但不是所有的命令都支持正则表达式,常见的命令中只有grep、sed、awk命令支持正则表达式.
-
定位符
定位符使用技巧:同时锚定开头和结尾,做精准匹配;单一的锚定开头和结尾,做模糊匹配
定位符 说明 ^ 锚定开头^a 以a开头,默认锚定一个字符 $ 锚定结尾a$ 以a结尾,默认锚定一个字符 egrep 等同于 grep -E #egrep "^ac$" file --精确匹配file中的内容 #egrep "^a" file --匹配file中以a开头的内容
-
匹配符:匹配字符串
匹配符 说明 . 匹配除回车以外的任意字符 ( ) 字符串分组 [ ] 定义字符类,匹配括号中的一个字符 [ ^ ] 表示否定括号中出现字符类中的字符,取反 转义字符 | (a|b) 匹配a或b -
限定符:对前面的字符或者字符串做限定说明
限定符 说明 * 某个字符之后加星号表示该字符不出现或出现多次 ? 与星号相似,表示该字符出现一次或不出现 + 与星号相似,表示其前面字符出现一次或多次,但必须出现一次 {n, m} 某个字符之后出现,表示该字符最少n次,最多m次 {m} 正好出现了m次 -
POSIX特殊字符
特殊字符 说明 [:alnum:] 匹配任意字母字符0-9 a-z A-Z [:alpha:] 匹配任意字母,大写或小写 [:digit:] 数字0-9 [:graph:] 非空字符(非空格控制字符) [:lower:] 小写字符a-z [:upper:] 大写字符A-Z [:cntrl:] 控制字符 [:print:] 非空字符(包括空格) [:punct:] 标点符号 [:blank:] 空格和TAB字符 [:xdigit:] 16进制数字 [:space:] 所有空白字符(新行、空格、制表符) --注意 [[]] 双中括号的意思:第一个中括号是匹配符[],匹配中括号中的任意一个字符,第二个[]是格式 如[:digit:] #egrep "^a[[:alnum:]]c$" file
16 shell对文件的操作
-
简介
在shell脚本编写中,时常会用到对文件的相关操作,比如增加内容,修改内容,删除部分内容,查看部分内容等,可以通过perl、sed等命令来实现上述功能.
-
sed命令
-
sed简介
sed是Linux中提供的一个外部命令,它是一个行(流)编辑器,非交互式的对文件内容进行增删改查的操作,使用者只能在命令行输入编辑命令、指定文件名,然后在屏幕上查看输出.
sed和文本编辑器的本质区别: 文本编辑器:编辑对象是文件 行编辑器:编辑对象是文件中的行
-
sed数据处理原理
sed处理数据原理 文本中的一行————————————>缓存————————————>电脑屏幕 数据在缓存中处理,然后默认输出到屏幕
-
sed命令
**语法: **
sed [options] '{command}[flags]' [filename]
--命令选项 -e script 将脚本中指定的命令添加到处理输入时执行的命令中 多条件,一行中要有多个操作 -f script 将文件中指定的命令添加到处理输入时执行的命令中 -n 抑制自动输出 -i 编辑文件内容 -i.bak 修改时同时创建.bak备份文件 -r 使用扩展的正则表达式 ! 取反, (跟在模式条件后与shell有所区别) --sed常用内部命令 a 在匹配后面添加 i 在匹配前面添加 p 打印 d 删除 s 查找替换 c 更改 y 转换 N D P --flags 数字 表示新文本替换的模式 g: 表示用新文本替换现有文本的全部实例 p: 表示打印原始的内容 w filename: 将替换的结果写入文件
#sed 'ahello world' data #sed '3ahello world' data #sed '2,4ahello world' data #sed '/3 the/ahello world' data --前面两个/,表示匹配模式
-
17 shell_awk基本语法
-
awk介绍
awk是一种可以处理数据、产生格式化报表的语言.
awk认为文件中的每一行是一条记录, 记录与记录的分隔符为换行符,每一列是一个字段,字段与字段的分隔符默认是一个或多个空格或tab制表符.
awk的工作方式是读取数据,将每一行数据视为一条记录(record),每条记录以字段分隔符分成若干字段,然后输出各个字段的值.
--awk语法 awk [options] [BEGIN]{program}[END][file] --常用命令选项 -F fs 指定描绘一行中数据字段的文件分隔符 默认为空格 -f file 指定读取程序的文件名 -v var=value 定义awk程序中使用的变量和默认值 --注意 awk程序脚本由左打括号和右大括号定义.脚本命令必须放置在两个大括号之间. --awk程序运行优先级是 1.BEGIN: 在开始处理数据流之前执行,可选项 2.program: 如何处理数据流,必选项 3.END: 处理完数据流后执行,可选项
-
awk基本用法
-
awk对字段(列)的提取
字段提取:提取一个文本中的一列数据并打印输出 --字段相关内置变量 $0 表示整行文本 $1 表示文本行中的第一个数据字段 $2 表示文本行中的第二个数据字段 $N 表示文本行中的第N个数据字段 $NF 表示文本行中的最后一个数据字段
#awk '{print $0}' test
-
命令选项详解
-F 指定字段与字段的分隔符 当输出的数据流字段格式不是awk默认的字段格式时,我们可以使用-F命令选项来重新定义数据流字段分隔符 #awk -F ":" '{print $1,$3,$NF}' passwd
-
awk对记录(行)的提取
记录提取: 提取一个文本中的一行并打印输出 记录的提取方法有两种: a.通过行号 b.通过正则匹配 记录相关内置变量 NR:指定行号 #awk 'NR==3{print $0}' test
-
awk对字符串提取
记录和字段的汇合点就是字符串 --打印test第三行的第六个字段 #awk 'NR==3{print $6}' test
-
awk程序的优先级
BEGIN是优先级最高的代码块,是在执行PROGRAM之前执行的,不需要提供数据源,因为不涉及到任何数据的处理,也不依赖与PROGRAM代码块; PROGRAM是让数据流干什么,是必选代码块,也是默认代码块,所以在执行时必须提供数据源; END是处理完数据流后的操作,如果需要执行END代码块,就必须要PROGRAM的支持,单个无法执行 #awk 'BEGIN{print "hello world"}{print $0}END{print "bye world"}' test
-
-
awk高级用法
awk是一门语言,除了可以定义变量外,还可以定义数组,可以进行运算及流程控制
-
awk定义数组
数组定义方式: 数组名[索引]=值
- 定义数组array,有两个元素,分别是100,200,打印数组元素 # awk 'BEGIN{array[0]=100;array[1]=200};print array[0],array[1]'
-
awk运算
1.赋值运算 = 2.比较运算 >,>=,==,<,<=,!= 3.数学运算 +,-,*,/,%,**,++,-- 4.逻辑匹配 &&,|| 5.匹配运算 ~,!~
-
awk环境变量
变量 描述 FIELDWIDTHS 以空格分隔的数字列表,用空格定义每个数据字段的精确宽度 FS 输入字段分隔符号 OFS 输出字段分隔符号 RS 输入记录分隔符 ORS 输出记录分隔符号 # awk 'BEGIN{FS=":"}$1 !~ "ro"{print $0}' passwd
-
流程控制
-
if判断语句
# awk '{ if ($1>5) print $0 else print $1*2 }' file_name -当该语句,写成一行时,需要加;作为分隔符 # awk '{if ($1<5)print $1*2;else print $1/2}' file_name
-
for循环语句
# awk '{sum=0;for (i=1;i<5;i++){sum+=$i}print sum}' file_name # awk '{ sum=0 for (i=0;i<4;i++){ sum+=$i } print sum }' file_name
-
while循环语句
awk '{ sum=0 i=1 while (i<4){ sum+=$i i++ } print sum }' file_name
-
do...while语句
awk '{ sum=0 i=1 do { sum+=$i i++ }while (sum<150) print sum }' file_name
-
循环控制
break 跳出循环,继续执行后续语句
-
-
-
awk小技巧
- 打印test文本的行数 # awk 'END{print NR}' file_name - 打印file_name文本最后一行内容 # awk 'END{print $0}' file_name - 打印test文本列数 # awk 'END{print NF}' test