今天我们开始学习shell编程语言
一、Shell脚本语言的基本结构
1、Shell脚本的用途:
自动化常用命令
执行系统管理和故障排除
创建简单的应用程序
处理文本或文件
2、 Shell脚本基本结构:
Shell脚本编程:是基于过程式,解释执行的语言
编程语言函数:指将具有特定功能的代码编写在一个有限的区块内并且取名
编程语言的基本结构:
各种系统命令的组合
数据存储:变量,数组,变量赋值:变量名=$(赋值符)
表达式:a+b
控制语句:if······then······条件语句、case、for循环语句、while
shell脚本:包含一些命令或声明,并符合一定格式的文本文件(写shell脚本时一定严格按照规范写,脚本名一定要用英文表示)
格式要求:首行执行shebang机制
#声明后续语句是通过那种语言写的
#!/bin/bash
#!/usr/bin/python
#!/usr/bin/perl
3、 创建Shell脚本过程
1.使用vim创建文本文件,第一行必须包括shell声明序列:
[root@localhost ~]# vim one.sh
#!/bin/bash
#name:lll
#版本号:1.1.1
#time:2025.1.1
#随便
#无注意事项
#无需更新
echo "my hostname is 'nblt'"
echo "Time is 'date +'%F %T''"
2.加执行权限,给予执行权限,在命令行上指定脚本的绝对或相对路径
[root@localhost ~]# chmod +x one.sh
3.运行脚本,直接运行解释器,将脚本作为解释器程序的参数运行
[root@localhost ~]# /root/one.sh
my hostname is 'nblt'
Time is 'date +'%F %T''
4、 脚本注释规范
第一行一般为调用使用的语言
程序名,避免更改文件名为无法找到正确的文件
版本号
更改后的时间
作者相关信息
该程序的作用,及注意事项
最后是各版本的更新简要说明
5、第一个脚本
[root@localhost ~]# cat one.sh
#!/bin/bash
#name:lll
#版本号:1.1.1
#time:2025.1.1
#随便
#无注意事项
#无需更新
echo "my hostname is 'nblt'"
echo "Time is 'date +'%F %T''"
[root@localhost ~]# chmod +x one.sh
[root@localhost ~]# /root/one.sh
my hostname is 'nblt'
Time is 'date +'%F %T'
6、 执行脚本
1、增加执行权限,执行脚本时会创建一个子shell,不影响现有的shell环境
[root@localhost ~]# chmod +x one.sh
[root@localhost ~]# ./one.sh
my hostname is 'nblt'
Time is 'date +'%F %T''
[root@localhost ~]# /root/one.sh
my hostname is 'nblt'
Time is 'date +'%F %T''
2、使用 . 或者source,执行脚本时不会创建一个子shell,会影响现有的shell环境
source one.sh . one.sh
注意:尽量不要使用该方式执行脚本!!!
7、脚本错误
语法错误,会导致后续的命令不继续执行,可以用bash -n shellname检查错误
命令错误,后续的命令还会继续,可以使用bash -x shellname检查
逻辑错误,只能使用bash -x进行观察
二、Shell脚本语言的变量用法详解
1、变量
变量表示命名的内存空间,将数据放在内存空间中,通过变量名引用,获取数据
2、 变量类型
变量类型:
内置变量:如PS1,PATH,UID,HOSTNAME,HISTSIZE
用户自定义变量
预定义变量
位置变量
不同的变量存放的数据不同,决定了以下:
数据存储方式
参与的计算
表示的数据范围
变量数据类型:
字符串
数值:整型,浮点型(小数)、bash不支持浮点数
3、 Shell中变量命名法则
不能使用程序中的保留字,如:if,for
只能使用数字,字母及下划线,且不能以数字开头
见名思意,用英文名字,并体现真正含义
统一命名规则:驼峰命名法
全局变量名大写
局部变量小写
函数名小写
4、 变量定义和引用
变量的生效范围(变量作用域)
普通变量:生效范围为当前shell进程;对当前shell之外的其他shell进程,包括当前shell的子shell进程均无效
环境变量:生效范围为当前shell进程及其子进程
本地变量:生效范围为当前shell进程中某代码片段,通常指函数
变量赋值:
name="value" value可以是以下多种类型 直接字符串:name='root' 变量引用:name="$USER" 命令应用:name=`command` || name=$(command) 通配符:FILE=/etc/* /*表示etc目录下所有的文件名*/
注意:变量赋值是临时生效,当退出终端后,变量会自动删除,无法持久保存。
变量引用:
$name ${name}
弱引用和强引用:
“$name”:弱引用,其中的变量引用会被替换成为变量值
‘$name’:强引用,其中的变量引用不会被替换成变量值,而保持原字符串
实例:
[root@localhost ~]# name='MIKE'
[root@localhost ~]# NAME="$USER"
[root@localhost ~]# hostname=`hostname`
[root@localhost ~]# echo "My name is $name"
My name is MIKE
[root@localhost ~]# echo "My name is $NAME"
My name is root
[root@localhost ~]# echo "My hostname is $hostname"
My hostname is localhost
[root@localhost ~]#
[root@localhost ~]# NUM=`seq 10`
[root@localhost ~]# echo $NUM
1 2 3 4 5 6 7 8 9 10
[root@localhost ~]# echo "$NUM"
1
2
3
4
5
6
7
8
9
10
[root@localhost ~]#
查看已定义的所有变量:
[root@localhost ~]# set
删除变量
实例:
[root@localhost ~]# name=Mike
[root@localhost ~]# echo $name
Mike
[root@localhost ~]# unset name
[root@localhost ~]# echo $name
实例:"{}"的使用
[root@localhost ~]# name=mage
[root@localhost ~]# age=20
[root@localhost ~]# echo $name
mage
[root@localhost ~]# echo $name $age
mage 20
[root@localhost ~]# echo $name_$age
20
[root@localhost ~]# echo ${name}_$age
mage_20
[root@localhost ~]#
利用变量实现动态命令
[root@localhost ~]# CMD=hostname
[root@localhost ~]# $CMD
localhost
[root@localhost ~]#
5、 环境变量
环境变量:
可以使子进程(包括孙子进程)继承父进程的变量,但是无法让父进程使用子进程的变量。
一旦子进程修改了从父进程继承的变量,将会传递新的值给孙子进程
一般只在配置文件中使用,在脚本中较少使用
课程引入:普通变量生效的范围与环境变量生效的范围
[root@localhost ~]# vim father.sh
#!/bin/bash
name=father
echo "father.sh:name=$name"
echo "fatther is PID=$BASHPID"
./son.sh
[root@localhost ~]# vim son.sh
#!/bin/bash
echo "son.sh:name=$name"
name=son
echo "son.sh:name=$name"
echo "son.sh PID is $BASHPID"
echo "son.sh father pid is $PPID"
[root@localhost ~]# chmod -R +x /*
[root@localhost ~]# ./father.sh
father.sh:name=father
fatther is PID=110924
son.sh:name=
son.sh:name=son
son.sh PID is 110925
son.sh father pid is 110924
变量声明和赋值:
export name=VALUE declare -x name =VALUE #或者先赋值再声明~ value可以是以下多种类型 直接字符串:name='root' 变量引用:name="$USER" 命令应用:name=`command` || name=$(command) 通配符:FILE=/etc/* /*表示etc目录下所有的文件名*/
{declare命令详解:(了解)
declare 为 shell 指令,在第一种语法中可用来声明变量并设置变量的属性([rix]即为变量的属性),在第二种语法中可用来显示 shell 函数。若不加上任何参数,则会显示全部的 shell 变量与函数(与执行 set 指令的效果相同)
语法
declare [+/-][rxi][变量名称=设置值] 或 declare -f
参数说明:
+/- "-“可用来指定变量的属性,”+"则是取消变量所设的属性。
-f 仅显示函数
r 将变量声明为只读变量。注意,一旦设置为只读变量,既不能修改变量的值也不能删除变量,甚至不能通过+r取消只 读属性
x 指定的变量会成为环境变量,可供shell以外的程序来使用
i 将变量声明为整数型(integer)
p 显示指定变量的被声明类型。
实例
1.声明整数型变量
#!/bin/bash declare -i ab //声明整数型变量 ab=56 //改变变量内容 echo $ab //显示变量内容 ---> 56
改变变量属性
#!/bin/bash #声明整数型变量 declare -i ef ef=1 echo $ef #变量赋值,赋予文本值 ef="wer" echo $ef #取消变量属性 declare +i ef ef="wer" echo $ef
3.设置变量只读
#!/bin/bash declare -r ab #设置变量为只读 ab=88 #改变变量内容 echo $ab #显示变量内容 ---> declare.sh:行3: ab: 只读变量
4.声明数组变量
#!/bin/bash #声明数组变量 declare -a cd cd[0]=a cd[1]=b cd[2]=c #输出数组的指定内容 echo ${cd[1]} #显示整个数组变量内容 echo ${cd[@]}
5.显示函数
#!/bin/bash #声明函数 declare -f function command_not_found_handle(){if [ -x /usr/lib/command_not_found_handle ];then/usr/bin/python /usr/lib/command_not_found_handle -- $1;return $?;elseif [ -x /usr/share/command_not_found_handle ];then/usr/bin/python /usr/share/command_not_found_handle --$1;return $?;elsereturn 127;fi;fi; }
变量引用:
$name ${name}
完善课程导入:
[root@localhost ~]# vim shell/father.sh #!/bin/bash NAME=father export NAME echo "father.sh:NAME=$NAME" echo "fatther is PID=$BASHPID" shell/son.sh [root@localhost ~]#vim shell/son.sh #!/bin/bash echo "son.sh:NAME=$NAME" NAME=son echo "son.sh:NAME=$NAME" echo "son.sh PID is $BASHPID" echo "son.sh father pid is $PPID" sleep 100 [root@localhost ~]#chmod -R +x shell/* [root@localhost ~]# ./shell/father.sh father.sh:NAME=father fatther is PID=12053 son.sh:NAME=father son.sh:NAME=son son.sh PID is 12054 son.sh father pid is 12053 [root@localhost ~]# ./shell/father.sh father.sh:NAME=father fatther is PID=12142 son.sh:NAME=father son.sh:NAME=son son.sh PID is 12143 son.sh father pid is 12142#父进程定义了一个环境变量,在子进程上可以进行调用#父进程无法使用子进程的变量#子进程自己定义了一个同名变量,就覆盖环境变量
显示所有环境变量:
[root@localhost ~]# env [root@localhost ~]# printenv [root@localhost ~]# export [root@localhost ~]# declare -x
删除变量
[root@localhost ~]#unset shellname1 shellname2
Bash内建的环境变量
PATH SHELL USER UID PWD SHLVL #shell的嵌套层数,即深度 LANG MAIL HOSTNAME HISTSIZE _ #下划线,表示前一命令的最后一个参数
6、只读变量
只读变量:只能声明定义,但后续不能修改和删除
声明只读变量:
readonly name declare -r name
查看只读变量:
readonly [-p] declare -r
}
7、位置与预定义变量
位置变量:在Bash Shell中内置的变量,在脚本代码中调用命令行传递给脚本的参数
$1,$2,... 对应第一个,第二个等参数,shift[n]换位置,最多9个 #预定义变量 $0 命令本身,包括路径 $* 传递给脚本的所有参数,全部参数合成一个字符串 $@ 传递给脚本的所有参数,每个参数为独立字符串 $# 传递给脚本的参数的个数 $? 上个命令的退出状态,或函数的返回值 $$ 当前shell进程ID。对于Shell脚本,就是这些脚本所在的进程ID 注意:$@,$*只有被双引号括起来的时候才会有差异
清空所有位置变量
set -- //写在脚本内部
实例演示1:
[root@localhost ~]# vim ARG.sh
#!/bin/bash
echo "1st arg is $1"
echo "2st arg is $2"
echo "3st arg is $3"
echo "4st arg is $4"
echo "The number of are is $#"
echo "All args are $*"
echo "All args are $@"
echo "The scriptname is `basename $0`"
[root@localhost ~]# chmod +x ARG.sh
[root@localhost ~]# ./ARG.sh {1..10}
1st arg is 1
2st arg is 2
3st arg is 3
4st arg is 4
The number of are is 10
All args are 1 2 3 4 5 6 7 8 9 10
All args are 1 2 3 4 5 6 7 8 9 10
The scriptname is ARG.sh
[root@localhost ~]#
8、 退出状态码变量
进程执行后,将使用变量 ? 保存状态码的相关数字,不同的值反应成功与失败, ?保存状态码的相关数字,不同的值反应成功与失败, ?保存状态码的相关数字,不同的值反应成功与失败,的取值范围为[0,255]
$?的值为0 代表成功 $?的值不为0 代表失败
用户可以在脚本中使用以下命令自定义退出状态码
exit [n]
实例:
[root@localhost ~]# ping -c 2 www.baidu.com > /dev/null
[root@localhost ~]# echo $?
0
[root@localhost ~]# cmd
-bash: cmd: 未找到命令
[root@localhost ~]# echo $?
127
[root@localhost ~]#
9、 展开命令行
9.1展开命令执行顺序
把命令行分成单个命令词 展开别名 展开大括号的声明{} 展开波浪符声明(~) 命令替换$()和`` 再次把命令行分成命令词 展开文件通配(*,?,[abc]等) 准备I/O重导向(<,>) 运行命令
9.2 防止扩展
反斜线(\)会使随后的字符按原意解释
实例:
[root@localhost ~]# echo Your cost:\$5.00
Your cost:$5.00
[root@localhost ~]#
9.3 加引号来防止扩展
单引号(' ')防止所有扩展 双引号(" ")可防止扩展,但是以下清空例外:$(美元符号)
9.4 变量扩展
``:反引号,命令替换 \:反斜线,禁止单个字符扩展 !:叹号,历史命令替换