Shell
1、Shell脚本
就是将需要执行的命令保存到文本中,按照顺序执行。它是解释型的,意味着不需要编译
1.1、基本写法
-
脚本第一行,#!指定解释器
#!/bin/bash
:表示使用bash解释器解析注意: 如果直接将解释器路径写死在脚本里,可能在某些系统就会存在找不到解释器的兼容性问题,所以可以使用:
#!/bin/env 解释器
-
脚本第二部分,注释(#号)说明,对脚本的基本信息进行描述【可选】
-
脚本第三部分,脚本要实现的具体代码内容
#!/bin/env bash # 以下内容是对脚本的基本信息的描述 # Name: 名字 # Desc:描述describe # Path:存放路径 # Usage:用法 # Update:更新时间 #下面就是脚本的具体内容 commands ...
1.2、执行方法
标准脚本执行方法
-
编写第一个shell脚本
[root@myhost shell01]# cat first_shell.sh #!/bin/env bash # 以下内容是对脚本的基本信息的描述 # Name: first_shell.sh # Desc: num1# Path: /shell01/first_shell.sh # Usage:/shell01/first_shell.sh # Update:2019-05-05 echo "hello world" echo "hello world" echo "hello world"
-
脚本增加可执行权限:
chmod +x first_shell.sh
-
标准方式执行脚本
/shell01/first_shell.sh
:绝对路径./first_shell.sh
:相对路径
非标准的执行方法
-
直接在命令行指定解释器执行
-
bash first_shell.sh
-
sh first_shell.sh
-
-
使用 source 命令读取脚本文件,执行文件里的代码
source first_shell.sh
1.3、注释
-
单行注释格式:# 这是一个注释
-
多行注释格式:
:<<EOF 注释内容... 注释内容... 注释内容... EOF 说明:EOF 也可以使用其他符号
2、变量
变量是用来临时保存数据的,该数据是可以变化的数据。
2.1、变量定义
变量名=变量值
-
变量名:用来临时保存数据的
-
变量值:就是临时的可变化的数据
[root@myhost ~]# A=hello 定义变量A [root@myhost ~]# echo $A 调用变量A hello [root@myhost ~]# echo ${A} 还可以这样调用 hello [root@myhost ~]# A=world 因为是变量所以可以变 [root@myhost ~]# echo $A world [root@myhost ~]# unset A 删除变量 [root@myhost ~]# echo $A
2.2、变量的定义规则
-
变量名区分大小写
[root@myhost ~]# A=hello [root@myhost ~]# a=world [root@myhost ~]# echo $A hello [root@myhost ~]# echo $a
-
变量名不能有特殊符号
[root@myhost ~]# *A=hello -bash: *A=hello: command not found [root@myhost ~]# ?A=hello -bash: ?A=hello: command not found [root@myhost ~]# @A=hello -bash: @A=hello: command not found # 特别说明:对于有空格的字符串给变量赋值时,要用引号引起来
-
变量名不能以数字开头
[root@myhost ~]# 1A=hello -bash: 1A=hello: command not found [root@myhost ~]# A1=hello # 注意:不能以数字开头并不代表变量名中不能包含数字。
-
等号两边不能有任何空格
[root@myhost ~]# A =123 -bash: A: command not found [root@myhost ~]# A= 123 -bash: 123: command not found [root@myhost ~]# A = 123 -bash: A: command not found [root@myhost ~]# A=123 [root@myhost ~]# echo $A 123
-
变量名尽量做到见名知意
注:bash中的引号
-
双引号""
:会把引号的内容当成整体来看待,允许通过$符号引用其他变量值 -
单引号''
:会把引号的内容当成整体来看待,禁止引用其他变量值,shell中特殊符号都被视为普通字符 -
反撇号`` :反撇号和$()一样,引号或括号里的命令会优先执行,如果存在嵌套,反撇号不能用
[root@myhost dir1]# echo "$(hostname)" myhost [root@myhost dir1]# echo '$(hostname)' $(hostname) [root@myhost dir1]# echo "hello world" hello world [root@myhost dir1]# echo 'hello world' hello world [root@myhost dir1]# echo $(date +%Y) 2018 [root@myhost dir1]# echo `date +%Y` 2018 [root@myhost dir1]# echo `echo `date +%Y`` date +%Y [root@myhost dir1]# echo `echo $(date +%Y)` 2018 [root@myhost dir1]# echo $(echo `date +%Y`) 2018 # 注: # echo -e "hello\nworld\c" # -e 开启转义 \n:换行 \c:不换
2.3、变量的定义方式
-
直接赋值给一个变量
[root@myhost ~]# A=1234567 [root@myhost ~]# echo $A 1234567 [root@myhost ~]# echo ${A:2:4} 3456
说明:$变量名 和 ${变量名}的异同
- 相同点:都可以调用变量
- 不同点: 变量名可以只截取变量的一部分,而 {变量名}可以只截取变量的一部分,而 变量名可以只截取变量的一部分,而变量名不可以,方便拼接
-
命令执行结果赋值给变量
[root@myhost ~]# B=`date +%Y` [root@myhost ~]# echo $B 2019 [root@myhost ~]# C=$(hostname) [root@myhost ~]# echo $C myhost
-
交互式定义变量(read)
-
目的:让用户自己给变量赋值,比较灵活。
-
语法:
read [选项] 变量名
-
常见选项
-
# 用法1:用户自己定义变量值
[root@myhost ~]# read name
harry
[root@myhost ~]# echo $name
harry
[root@myhost ~]# read -p "Input your name:" name
Input your name:tom
[root@myhost ~]# echo $name
tom
# 用法2:变量值来自文件
[root@myhost ~]# cat 1.txt
abc
[root@myhost ~]# read c < 1.txt
[root@myhost ~]# echo $c
abc
# # # # # # # # # #
Linux 的IO(input output):
3种情况:
0 标准输入 - stdin
1 标准输出 - stdout
2 错误输出 - stderr
/dev/null:Linux中的黑洞位置。
>/dev/null 2>&1:将结果以标准输出和错误输出到黑洞中。
ps -ef | grep mysql >/dev/null 2>&1
<:输入文本内容。
>:将结果写入到文件,内容会被覆盖。
>>:将结果追加写入到文件末尾,内容不会被覆盖。
-
定义有类型的变量(declare)
- 目的:给变量做一些限制,固定变量的类型,比如:整型、只读
- 用法: declare 选项 变量名=变量值
- 常用选项:
[root@myhost ~]# declare -i A=123 [root@myhost ~]# echo $A 123 [root@myhost ~]# A=hello [root@myhost ~]# echo $A 0 [root@myhost ~]# declare -r B=hello [root@myhost ~]# echo $B hello [root@myhost ~]# B=world -bash: B: readonly variable [root@myhost ~]# unset B -bash: unset: B: cannot unset: readonly variable
2.4、变量的分类
-
本地变量 :当前用户自定义的变量。当前进程中有效,其他进程及当前进程的子进程无效
-
环境变量:当前进程有效,并且能够被子进程调用
- env:查看当前用户的环境变量
- set:查询当前用户的所有变量(临时变量与环境变量)
- export 变量名=变量值
- 变量名=变量值 export 变量名
[root@myhost ~]# export A=hello 临时将一个本地变量(临时变量)变成环境变量 [root@myhost ~]# env|grep A A=hello # 永久生效: [root@myhost ~]# vi /etc/profile 或者 ~/.bash_profile export A=hello source .bash_profile
-
全局变量:全局所有的用户和程序都能调用,且继承,新建的用户也默认能调用
- 说明:以上文件修改后,都需要重新source让其生效或者退出重新登录
- 用户登录系统读取相关文件的顺序
/etc/profile
$HOME/.bash_profile
$HOME/.bashrc
etc/bashrc
$HOME/.bash_logout
-
系统变量(内置bash中变量) : shell本身已经固定好了它的名字和作用
#!/bin/bash #了解shell内置变量中的位置参数含义 echo "\$0 = $0" echo "\$# = $#" echo "\$* = $*" echo "\$@ = $@" echo "\$1 = $1" echo "\$2 = $2" echo "\$3 = $3" echo "\$11 = ${11}" echo "\$12 = ${12}" 进一步了解$*和$@的区别 $* :表示将变量看成一个整体 $@ :表示变量是独立的 #!/bin/bash for i in "$@" do echo $i done echo "======我是分割线=======" for i in "$*" do echo $i done [root@myhost ~]# bash 3.sh a b c a b c ======我是分割线======= a b c
3、简单四则运算
- 算术运算:默认情况下,shell就只能支持简单的整数运算
- 运算内容:加(+)、减(-)、乘(*)、除(/)、求余数(%)
-
四则运算符号
-
expr
符号两侧需要空格 -
expr \( 1 + 2 \) \* 3
小括号和乘号需要转义
-
-
i++和++i
# 对变量的值的影响 [root@myhost ~]# i=1 [root@myhost ~]# let i++ [root@myhost ~]# echo $i 2 [root@myhost ~]# j=1 [root@myhost ~]# let ++j [root@myhost ~]# echo $j 2 # 对表达式的值的影响 [root@myhost ~]# unset i j [root@myhost ~]# i=1;j=1 [root@myhost ~]# let x=i++ 先赋值,再运算 [root@myhost ~]# let y=++j 先运算,再赋值 [root@myhost ~]# echo $i 2 [root@myhost ~]# echo $j 2 [root@myhost ~]# echo $x 1 [root@myhost ~]# echo $y 2
4、数组
-
数组分类
- 普通数组:只能使用整数作为数组索引(元素的下标)
- 关联数组:可以使用字符串作为数组索引(元素的下标)
-
普通数组定义
# 一次赋予一个值,数组名[索引下标]=值 [root@myhost ~]# array[0]=v1 [root@myhost ~]# array[1]=v2 [root@myhost ~]# array[3]=v3 # 一次赋予多个值,数组名=(值1 值2 值3 ...) [root@myhost ~]# array=(var1 var2 var3 var4) [root@myhost ~]# array1=(`cat /etc/passwd`) # 将文件中每一行赋值给array1数组 [root@myhost ~]# array2=(`ls /home/tom`) [root@myhost ~]# array3=(harry amy jack "jerry") [root@myhost ~]# array4=(1 2 3 4 "hello world" [10]=linux)
-
数组的读取
# ${数组名[元素下标]} [root@myhost ~]# echo ${array[0]} # 获取数组里第一个元素 [root@myhost ~]# echo ${array[*]} # 获取数组里的所有元素 [root@myhost ~]# echo ${#array[*]} # 获取数组里所有元素个数 [root@myhost ~]# echo ${!array[@]} # 获取数组元素的索引下标 # 访问指定的元素;1代表从下标为1的元素开始获取;2代表获取后面几个元素 [root@myhost ~]# echo ${array[@]:1:2} # @和*通用 # 查看普通数组信息: [root@myhost ~]# declare -a
-
关联数组定义
# 1、首先声明关联数组 [root@myhost ~]# declare -A asso_array1 [root@myhost ~]# declare -A asso_array2 [root@myhost ~]# declare -A asso_array3 # 2、数组赋值 #一次赋一个值,数组名[索引or下标]=变量值 [root@myhost ~]# asso_array1[linux]=one [root@myhost ~]# asso_array1[java]=two [root@myhost ~]# asso_array1[php]=three # 一次赋多个值 [root@myhost ~]# asso_array2=([name1]=harry [name2]=jack [name3]=amy [name4]="jack") # 查看关联数组 # declare -A [root@myhost ~]# declare -A asso_array1='([php]="three" [java]="two" [linux]="one" )' [root@myhost ~]# declare -A asso_array2='([name3]="amy" [name2]="jack" [name1]="harry" [name4]="jack" )' # 获取关联数组值 [root@myhost ~]# echo ${asso_array1[linux]} one # echo ${asso_array1[php]} [root@myhost ~]# three [root@myhost ~]# echo ${asso_array1[*]} three two one [root@myhost ~]# echo ${!asso_array1[*]} php java linux [root@myhost ~]# echo ${#asso_array1[*]} 3 [root@myhost ~]# echo ${#asso_array2[*]} 4 [root@myhost ~]# echo ${!asso_array2[*]} name3 name2 name1 name4
5、其他变量定义
# 取出一个目录下的目录和文件: dirname 和 basename
[root@myhost ~]# A=/root/Desktop/shell/mem.txt
[root@myhost ~]# echo $A
/root/Desktop/shell/mem.txt
[root@myhost ~]# dirname $A # 取出目录
/root/Desktop/shell
[root@myhost ~]# basename $A # 取出文件
mem.txt
# 变量"内容"的删除和替换
# 一个“%”代表从右往左去掉一个/key/
# 两个“%%”代表从右往左最大去掉/key/
# 一个“#”代表从左往右去掉一个/key/
# 两个“##”代表从左往右最大去掉/key/
# 举例说明:
[root@myhost ~]# url=www.taobao.com
[root@myhost ~]# echo ${#url} # 获取变量的长度
[root@myhost ~]# echo ${url#*.}
[root@myhost ~]# echo ${url##*.}
[root@myhost ~]# echo ${url%.*}
[root@myhost ~]# echo ${url%%.*}
# 替换:/ 和 //
[root@myhost ~]# echo ${url/ao/AO} # 替换第一个
[root@myhost ~]# echo ${url//ao/AO} # 替换所有
6、条件判断
-
条件判断语法格式
- 格式1:
test 条件表达式
- 格式2:
[ 条件表达式 ]
- 格式3:
[[ 条件表达式 ]]
- 格式1:
-
条件判断相关参数
可以判断文件类型,判断文件新旧,判断字符串是否相等,判断权限等等…
-
判断文件类型
# 举例说明: [root@myhost ~]# test -e file # 只要文件存在条件为真 [root@myhost ~]# [ -d /shell01/dir1 ] # 判断目录是否存在,存在条件为真 [root@myhost ~]# [ ! -d /shell01/dir1 ] # 判断目录是否存在,不存在条件为真 [root@myhost ~]# [[ -f /shell01/1.sh ]] # 判断文件是否存在,并且是一个普通的文件
-
判断文件权限
-
判断文件新旧
- 说明:这里的新旧指的是文件的修改时间
-
判断整数
-
判断字符串
-
多重条件判断
-
特别说明
&&
:前面的表达式为真,才会执行后面的代码||
:前面的表达式为假,才会执行后面的代码;
:只用于分割命令或表达式
① 举例说明
数值比较
[root@server ~]# [ $(id -u) -eq 0 ] && echo "the user is admin"
[root@server ~]$ [ $(id -u) -ne 0 ] && echo "the user is not admin"
[root@server ~]$ [ $(id -u) -eq 0 ] && echo "the user is admin" || echo "the user is not admin"
[root@server ~]# uid=`id -u`
[root@server ~]# test $uid -eq 0 && echo this is admin
this is admin
[root@server ~]# [ $(id -u) -ne 0 ] || echo this is admin
this is admin
[root@server ~]# [ $(id -u) -eq 0 ] && echo this is admin || echo this is not admin
this is admin
[root@server ~]# su - stu1
[stu1@server ~]$ [ $(id -u) -eq 0 ] && echo this is admin || echo this is not admin
this is not admin
类C风格的数值比较
注意:在(( ))中,=表示赋值;==表示判断
[root@server ~]# ((1==2));echo $?
[root@server ~]# ((1<2));echo $?
[root@server ~]# ((2>=1));echo $?
[root@server ~]# ((2!=1));echo $?
[root@server ~]# ((`id -u`==0));echo $?
[root@server ~]# ((a=123));echo $a
[root@server ~]# unset a
[root@server ~]# ((a==123));echo $?
字符串比较
注意:双引号引起来,看作一个整体;= 和 == 在 [ 字符串 ] 比较中都表示判断
[root@server ~]# a='hello world';b=world
[root@server ~]# [ $a = $b ];echo $? 错误代码
[root@server ~]# [ "$a" = "$b" ];echo $?
[root@server ~]# [ "$a" != "$b" ];echo $?
[root@server ~]# [ "$a" !== "$b" ];echo $? 错误
[root@server ~]# [ "$a" == "$b" ];echo $?
[root@server ~]# test "$a" != "$b";echo $?
# test 表达式
# [ 表达式 ]
# [[ 表达式 ]]
[root@server ~]# a=
[root@server ~]# test -z $a;echo $?
[root@server ~]# a=hello
[root@server ~]# test -z $a;echo $?
[root@server ~]# test -n $a;echo $?
[root@server ~]# test -n "$a";echo $?
[root@server ~]# [ '' = $a ];echo $?
1
[root@server ~]# [[ '' = $a ]];echo $?
0
[root@server ~]# [ 1 -eq 0 -a 1 -ne 0 ];echo $?
[root@server ~]# [ 1 -eq 0 && 1 -ne 0 ];echo $? 错误
[root@server ~]# [[ 1 -eq 0 && 1 -ne 0 ]];echo $?
② 逻辑运算符总结
-
符号;和&&和||都可以用来分割命令或者表达式
-
分号(;)完全不考虑前面的语句是否正确执行都会执行;号后面的内容
-
&& 符号,需要考虑&&前面的语句的正确性,前面语句正确执行才会执行&&后的内容;反之亦然
-
|| 符号,需要考虑||前面的语句的非正确性,前面语句执行错误才会执行||后内容;反之亦然
-
如果&&和||一起出现,从左往右依次看,按照以上原则
7、流程控制语句
7.1、if语句
# 1、if结构
if condition
then
command1
command2
...
commandN
fi
if condition; then
command1
command2
...
commandN
fi
# 2、if...else结构
if condition
then
command1
command2
...
commandN
else
command
fi
# 3、if...elif...else结构
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi
7.2、case语句
case var in # 定义变量;var代表是变量名
1) # 模式1;
command1 # 需要执行的语句
;; # 两个分号代表命令结束
2)
command2
;;
3)
command3
;;
*)
default,# 不满足以上模式,默认执行*)下面的语句
command4
;;
esac # esac表示case语句结束
7.3、for循环语句
-
列表循环
# 列表for循环:用于将一组命令执行已知的次数 # 基本语法格式 for variable in {list} do command command … done # 或者 for variable in a b c do command command done # 举例说明 for var in {1..10};do echo $var;done for var in 1 2 3 4 5;do echo $var;done for var in `seq 10`;do echo $var;done for var in $(seq 10);do echo $var;done for var in {0..10..2};do echo $var;done for var in {2..10..2};do echo $var;done for var in {10..1};do echo $var;done for var in {10..1..-2};do echo $var;done for var in `seq 10 -2 1`;do echo $var;done
-
不带列表循环
# 不带列表的for循环执行时由用户指定参数和参数的个数 # 基本语法格式 for variable do command command … done # 举例说明 #!/bin/bash for var do echo $var done /shell_test.sh 1 2 3 4 # echo "脚本后面有$#个参数"
-
类C风格的for循环
# 基本语法结构 for(( expr1;expr2;expr3 )) do command command … done for ((i=1;i<=5;i++)) do echo $i done # expr1:定义变量并赋初值 # expr2:决定是否进行循环(条件) # expr3:决定循环变量如何改变,决定循环什么时候退出 # 举例说明 for ((i=1;i<=5;i++));do echo $i;done for ((i=1;i<=10;i+=2));do echo $i;done for ((i=2;i<=10;i+=2));do echo $i;done
7.4、while循环语句
特点:条件为真就进入循环;条件为假就退出循环
# while循环语法结构
while 表达式
do
command...
done
while [ 1 -eq 1 ] 或者 (( 1 > 2 ))
do
command
command
...
Done
# 循环打印1-5数字
# FOR循环打印:
for ((i=1;i<=5;i++))
do
echo $i
done
# while循环打印:
i=1
while [ $i -le 5 ]
do
echo $i
let i++
done
7.5、until循环
特点:条件为假就进入循环;条件为真就退出循环
# until语法结构
until expression [ 1 -eq 1 ] (( 1 >= 1 ))
do
command
command
...
done
# 打印1-5数字
i=1
while [ $i -le 5 ]
do
echo $i
let i++
done
i=1
until [ $i -gt 5 ]
do
echo $i
let i++
done
7.6、循环控制语句
- continue:继续;表示循环体内下面的代码不执行,重新开始下一次循环
- break:打断;马上停止执行本次循环,执行循环体后面的代码
- exit:表示直接跳出程序
8、函数
8.1、函数概述
shell中允许将一组命令集合或语句形成一段可用代码,这些代码块称为shell函数,给这段代码起个名字称为函数名,后续可以直接调用该段代码的功能
8.2、函数定义
# 格式:
[function] 函数名()
{
函数体(一堆命令的集合,来实现某个功能)
[return int;]
}
函数中return说明
- return可以结束一个函数。
- return默认返回函数中最后一个命令状态值,也可以给定参数值,范围是0-256之间。
- 如果没有return命令,函数将返回最后一个指令的退出状态值。
8.3、函数调用
-
当前命令行调用
[root@tom shell04]# source fun1.sh [root@tom shell04]# hello [root@tom shell04]# hello 888 999
-
定义到用户的环境变量中
[root@tom shell05]# vi ~/.bashrc # 文件中增加如下内容: hello(){ echo "hello" } # 注意:当用户打开bash的时候会读取该文件
-
脚本中调用fun2
#!/bin/bash source ./fun1.sh fun2(){ echo "hello" } # 调用函数 fun2
9、正则表达式
9.1、正则表达式概述
正则表达式(Regular Expression、regex或regexp,缩写为RE),也译为正规表示法、常规表示法,是一种字符模式,用于在查找过程中匹配指定的字符。
- 正则的作用
- 匹配邮箱、匹配身份证号码、手机号、银行卡号等
- 匹配某些特定字符串,做特定处理等等
- 正则当中名词解释
- 元字符:指那些在正则表达式中具有特殊意义的专用字符,如:点 (.) 星(*) 问号 (?) 等
- 前导字符:位于元字符前面的字符
. abc* aooo.
9.2、shell脚本中使用正则表达式
#!/usr/bin/env bash
read -p "输入1个数字" num1
if [[ $num1 =~ ^-?[0-9]+$ ]]; then
echo '是整数'
fi