shell就是人机交互的一个桥梁 ;shell 本质上是 linux 命令,一条一条命令组合在一起,实现某一个目的,就变成了shell脚本。它从一定程度上 减轻了工作量,提高了工作效率。
官方概念:
Shell 通过提示您输入,向操作系统解释该输入,然后处理来自操作系统的任何结果输出,简单来说Shell就是一个用户跟操作系统之间的一个命令解释器。
.sh
#!/bin/bash
做为首行来指定解释器创建HelloWorld.sh
[root@node100 shell_test]# vim HelloWorld.sh
编写内容
#!/bin/bash
echo 'Hello World!!!'
# echo 为打印输出
执行脚本文件
① 给文件执行权限
[root@node100 shell_test]# chmod +x HelloWorld.sh
②执行脚本
# 相对路径执行
[root@node100 shell_test]# ./HelloWorld.sh
# 绝对路径执行
[root@node100 shell_test]# /shell_test/HelloWorld.sh
注意:bash中的引号
双引号"" :会把引号的内容当成整体来看待,允许通过$符号引用其他变量值
单引号'' :会把引号的内容当成整体来看待,禁止引用其他变量值,shell中特殊符号都被视为普通字符
反撇号`` :反撇号和$()一样,引号或括号里的命令会优先执行,如果存在嵌套,反撇号不能用
在编译过程中被解释器忽略的内容就称为注释。
单行注释
单行注释格式:
# 这是一个注释
多行注释
多行注释格式:
:<
变量是用来临时保存数据的,该数据是可以变化的数据。
定义语法:变量名=变量值
①定义变量
[root@node100 shell_test]# a=123
②调用变量
[root@node100 shell_test]# echo $a
或者
[root@node100 shell_test]# echo ${a}
③删除变量
[root@node100 shell_test]# unset a
以上变量用法在Shell脚本中也同样使用
①变量名区分大小写
②变量名不能有特殊符号
特别说明:对于有空格的字符串给变量赋值时,要用引号引起来;
③变量名不能以数字开头但可以包含数字
④等号两边不能有任何空格
⑤变量名尽量做到见名知意
①直接赋值给一个变量
[root@node100 shell_test]# a=123456789
[root@node100 shell_test]# echo ${a:2:3} # 表示从第3位开始截取,截取3个字符
345
说明:
$变量名
和${变量名}
的异同
相同点:相同点:都可以调用变量
不同点:${变量名}可以只截取变量的一部分,而$变量名不可以
②命令执行结果赋值给变量
[root@node100 shell_test]# a=`hostname`
[root@node100 shell_test]# echo $a
node100
[root@node100 shell_test]# b=$(date)
[root@node100 shell_test]# echo $b
2022年 07月 30日 星期六 13:59:22 KST
③交互式定义变量(read)
目的:让用户自己给变量赋值,比较灵活。
语法:read [选项] 变量名
常见选项
选项 | 解释 |
---|---|
-p |
定义提示用户的信息 |
-n |
定义字符数(现在变量长度) |
-s |
不显示(不显示用户的密码) |
-t |
定义超时时间,默认单位为秒(现在用户输入变量值的超时时间,单位为秒) |
举例1:让用户自己定义变量值
[root@node100 shell_test]# read -p "请输入你的名字" name
[root@node100 shell_test]# read -n6 a
[root@node100 shell_test]# read -s pwd
[root@node100 shell_test]# read -t1 a
举例2:变量值来自文件
注意:无论文件有多少内容,默认只取第一行内容作为变量值。
④定义有类型的变量(declare)
目的:给变量做一些限制,固定变量的类型,比如:整型、只读
用法:declare 选项 变量名=变量值
常用选项:
选项 | 解释 | 举例 |
---|---|---|
-i |
将变量看成整数 | declare -i A=123 |
-r |
定义只读变量 | declare -r B=hello |
-a |
定义普通数组;查看普通数组 | |
-A |
定义关联数组;查看关联数组 | |
-x |
将变量通过环境导出 | declare -x A=123456 等于 export A=123456 |
举例:
凡是被-i
选项修饰的变量,只能赋值整数。
凡是被-r
选项修饰的变量,为只读变量不能修改。
系统变量(内置bash中变量) : shell本身已经固定好了它的名字和作用.
内置变量 | 含义 |
---|---|
$? |
返回上一条命令的执行状态;0表示执行正常,非0表示执行异常或错误 |
$0 |
当前执行的程序和脚本名 |
$# |
脚本后面接的参数的个数 |
$* |
脚本后面所有参数,参数当成一个整体输出,每一个变量参数之间以空格隔开 |
$@ |
脚本后面所有参数,参数是独立的,也是全部输出 |
$1-$9 |
脚本后面的位置参数,$1 表示第一个位置参数,以此类推 |
${10}-${n} |
扩展位置参数,第10个位置变量必须用{}大括号括起来(2位数字以上括起来) |
$$ | 先前所在进程的进程号 |
$! |
后台运行的最后一个进程号 |
!$ |
调用最后一条命令历史中的参数 |
求变量长度:${#变量名}
[root@node100 shell_test]# q=123
[root@node100 shell_test]# echo ${#q}
替换:${变量/old/new}
将变量中第一次出现的old值替换成new值
[root@node100 shell_test]# url=www.baidu.com
[root@node100 shell_test]# echo ${url/w/x}
替换:${变量//old/new}
将变量中出现的old值全部替换成new值
[root@node100 shell_test]# echo ${url//w/x}
算术运算:默认情况下,shell就只能支持简单的整数运算
运算内容:加(+)、减(-)、乘(*)、除(/)、求余数(%)
表达式 | 举例 |
---|---|
$(()) |
echo $((1+1)) |
$[] |
echo $[10-5] |
expr |
expr 10 / 5 |
let |
n=1;let n+=1 等价于let n=n+1 |
注意:在使用expr
时一定要注意空格,而且在做乘法运算时一定要加引号,因为*
在Linux中表示通配符。
①$(())
②$[]
③expr
④let
i++
和++i
i++:先打印i,后进行加1操作
++i:先进行加1操作,后打印i
注意:除了i++
和++i
外,i--
和--i
;expr不支持i++
和++i
①一次赋予一个值
数组名[索引下标]=值
[root@node100 shell_test]# qwe[0]=1
[root@node100 shell_test]# qwe[1]=2
[root@node100 shell_test]# qwe[2]=3
访问:${数组名[元素下标]}
[root@node100 shell_test]# echo ${qwe[0]}
也可以通过declare -a 数组名
的方式去声明数组
②一次赋予多个值
数组名=(值1 值2 值3 ...)
[root@node100 shell_test]# asd=(v1 v2 v3)
访问:${数组名[元素下标]}
[root@node100 shell_test]# echo ${asd[0]}
③将文件中每一行赋值给数组
[root@node100 shell_test]# cat 1.txt
qwe
asd
zxc
rty
[root@node100 shell_test]# zxc=(`cat 1.txt`)
访问:${数组名[元素下标]}
[root@node100 shell_test]# echo ${zxc[0]}
①声明关联数组
声明方式:declare -A 数组名
[root@node100 shell_test]# declare -A array
②数组赋值
一次赋一个值
语法:数组名[索引or下标]=变量值
[root@node100 shell_test]# array[hello]=world
访问数组中的值
语法:echo ${数组名[索引or下标]}
一次赋多个值
语法:数组名=([下标1]=变量值1 [小标2]=变量值2 ... ...)
[root@node100 shell_test]# declare -A array2
[root@node100 shell_test]# array2=([1]=one [name]=tom [age]=18)
访问
语法:echo ${数组名[索引or下标]}
[root@node100 shell_test]# echo ${array2[1]}
访问数组中全部数据
[root@node100 shell_test]# echo ${array2[*]}
访问数组中的全部下标或索引名词
[root@node100 shell_test]# echo ${!array2[*]}
格式1: test 条件表达式
格式2: [ 条件表达式 ]
格式3: [[ 条件表达式 ]]
可以判断文件类型,判断文件新旧,判断字符串是否相等,判断权限等等..
①判断文件类型
判断参数 | 含义 |
---|---|
-e |
判断文件是否存在 |
-f |
判断文件是否存在并且是一个普通文件 |
-d |
判断文件是否存在并且是一个目录 |
-L |
判断文件是否存在并且是一个软连接文件 |
-b |
判断文件是否存在并且是一个块设备文件 |
-S |
判断文件是否存在并且是一个套接字文件 |
-c |
判断文件是否存在并且是一个字符设备文件 |
-p |
判断文件是否存在并且是一个命名管道文件 |
-s |
判断文件是否存在并且是一个非空文件(有内容) |
举例:test 条件表达式
[root@node100 shell_test]# test -e a
[root@node100 shell_test]# echo $?
举例:[ 条件表达式 ]
[root@node100 shell_test]# [ -e 1.txt ]
[root@node100 shell_test]# echo $?
举例:[[ 条件表达式 ]]
[root@node100 shell_test]# [[ -e 1.txt ]]
[root@node100 shell_test]# echo $?
②判断文件权限
判断参数 | 含义 |
---|---|
-r |
当前用户对其是否可读 |
-w |
当前用户对其是否可写 |
-x |
当前用户对其是否可执行 |
-u |
是否有suid,高级权限冒险位 |
-g |
是否有sgid,高级权限强制位 |
-k |
是否有t位,高级权限粘滞位 |
举例:
[root@node100 shell_test]# [ -r 1.txt ]
[root@node100 shell_test]# echo $?
[root@node100 shell_test]# [ -x 1.txt ]
[root@node100 shell_test]# echo $?
③判断文件新旧
说明:这里的新旧指的是文件的修改时间。
判断参数 | 含义 |
---|---|
file1 -nt file2 |
比较file1是否比file2新 |
file1 -ot file2 |
比较file1是否比file2旧 |
file1 -ef file2 |
比较是否为同一个文件 |
举例:
[root@node100 shell_test]# [ 1.txt -nt demo1.sh ]
[root@node100 shell_test]# echo $?
④判断整数
判断参数 | 含义 |
---|---|
-eq |
相等 |
-ne |
不等 |
-gt |
大于 |
-lt |
小于 |
-ge |
大于等于 |
-le |
小于等于 |
举例:
[root@node100 shell_test]# [ 1 -eq 1 ]
[root@node100 shell_test]# echo $?
⑤判断字符串
判断参数 | 含义 |
---|---|
-z |
判断是否为空字符串,字符串长度为0则成立 |
-n |
判断是否为非空字符串,字符串长度不为0则成立 |
string1 = string2 |
判断字符串是否相等 |
string1 != string2 |
判断字符串是否不相等 |
举例:
[root@node100 shell_test]# [ a = a ]
[root@node100 shell_test]# echo $?
⑥多重条件判断
判断符号 | 含义 | 举例 |
---|---|---|
-a和&& |
逻辑与 | [ 1 -eq 1 -a 1 -ne 0 ] 或者[ 1 -eq 1 ] && [ 1 -ne 0 ] |
-o | 逻辑或 | [ 1 -eq 1 -o 1 -ne 0 ] |
特别说明:
&& 前面的表达式为真,才会执行后面的代码
|| 前面的表达式为假,才会执行后面的代码
[root@node100 shell_test]# [ 2 -eq 2 ] && echo 'true'
[root@node100 shell_test]# [ 2 -eq 1 ] && echo 'true'||echo 'false'
注意:在(( ))中,=表示赋值;==表示判断
举例:
注意:;
只用于分割命令或表达式
语法结构:
① if结构
if condition
then
command1
command2
...
commandN
fi
② if...else结构
if condition
then
command1
command2
...
commandN
else
command
fi
③ if...elif...else结构
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi
举例:
编写if.sh
文件
#!/bin/bash
read -p "请输入你的年龄" age
if [ $age -ge 1 -a $age -le 18 ]
then
echo "年龄大于等于1并且小于等于18是未成年人"
elif [[ $age -gt 18 ]]
then
echo "年龄大于18是成年人"
else
echo "请输入正确的年龄"
fi
执行if.sh
文件
[root@node100 shell_test]# chmod +x if.sh
[root@node100 shell_test]# ./if.sh
语法结构
case 变量名 in
变量值1)
command1 需要执行的语句
;; 两个分号代表命令结束
变量值2)
command2
;;
变量值3)
command3
;;
*) default,不满足以上模式,默认执行*)下面的语句
command4
;;
esac
举例:
编写case.sh
文件
#!/bin/bash
read -p "请输入变量值" i
case $i in
1)
echo "你是第一名"
;;
2)
echo "你是第二名"
;;
3)
echo "你是第三名"
;;
*)
echo "你不是前三名"
;;
esac
执行
[root@node100 shell_test]# chmod +x case.sh
[root@node100 shell_test]# ./case.sh
语法结构:
①列表循环
列表for循环:用于将一组命令执行已知的次数
基本语法格式
for variable in {list}
do
command
command
…
done
或者
for variable in a b c
do
command
command
done
举例(控制台):
[root@node100 shell_test]# for i in {1..10};do echo $i;done
[root@node100 shell_test]# for i in 1 2 3;do echo $i;done
\
[root@node100 shell_test]# for i in {1..10..2};do echo $i;done
# {起始值..结束值..步长}
[root@node100 shell_test]# for i in {10..1..2};do echo $i;done
[root@node100 shell_test]# for i in $(seq 10);do echo $i;done
# seq是个命令 seq [起始值] [步长] [结束值]
②不带列表循环
for variable
do
command
command
…
done
举例:
编写for1.sh
#!/bin/bash
for i
do
echo $i
done
在执行的传参
[root@node100 shell_test]# chmod +x for1.sh
[root@node100 shell_test]# ./for1.sh 1 2 3
③类C风格的for循环
for(( expr1;expr2;expr3 ))
do
command
command
…
done
# expr1:初始条件
# expr2:循环条件
# expr3:迭代条件
举例:
编写for2.sh
文件
#!/bin/bash
for((i=1;i<=5;i++))
do
echo $i
done
执行
[root@node100 shell_test]# chmod +x for2.sh
[root@node100 shell_test]# ./for2.sh
特点:条件为真就进入循环;条件为假就退出循环
语法结构:
while 表达式
do
command...
done
举例:
编写while.sh
文件
#!/bin/bash
i=1
while ((i<=5)) # ((i<=5)) 也可以换成 [ $i -le 5 ]
do
echo $i
let i++
done
执行
[root@node100 shell_test]# chmod +x while.sh
[root@node100 shell_test]# ./while.sh
特点:条件为假就进入循环;条件为真就退出循环
语法结构
until expression
do
command
command
...
done
举例:
编写until.sh
文件
#!/bin/bash
i=1
until [ $i -gt 5 ]
do
echo $i
let i++
done
执行
[root@node100 shell_test]# chmod +x until.sh
[root@node100 shell_test]# ./until.sh
6.6、循环控制语句
continue:继续;表示循环体内下面的代码不执行,重新开始下一次循环
break:打断;马上停止执行本次循环,执行循环体后面的代码
exit:表示直接跳出程序
举例:循环打印1-5,但不打印3
编写continue.sh
#!/bin/bash
for((i=1;i<=5;i++))
do
if ((i==3))
then
continue
fi
echo $i
done
执行
[root@node100 shell_test]# vim continue.sh
[root@node100 shell_test]# ./continue.sh
举例:循环打印1-5,但是但是打印到3的时候结束循环
编写break.sh
文件
#!/bin/bash
for((i=1;i<=5;i++))
do
echo $i
if ((i==3))
then
break
fi
done
echo "程序结束"
执行
[root@node100 shell_test]# chmod +x break.sh
[root@node100 shell_test]# ./break.sh
举例:循环打印1-5,但是但是打印到3的时候结束整个程序
编写exit.sh
文件
#!/bin/bash
for((i=1;i<=5;i++))
do
echo $i
if ((i==3))
then
exit
fi
done
echo "结束程序"
执行
[root@node100 shell_test]# vim exit.sh
[root@node100 shell_test]# ./exit.sh
shell中允许将一组命令集合或语句形成一段可用代码,这些代码块称为shell函数,给这段代码起个名字称为函数名,后续可以直接调用该段代码的功能。
语法结构
[ function ] 函数名(){
命令代码
[ return [value]]
# 在return后面写一个值(0-256) 然后通过 echo $? 查看状态值。
# 若只写return则表示结束,return后面的代码将不会执行
命令代码
}
举例:编写求输入参数和的函数
编写fun.sh
文件
#!/bin/bash
function get_sum(){
sum=0
for i in $@
do
let sum+=i
done
return $sum # 也可以直接 echo
}
执行
[root@node100 shell_test]# source fun.sh # 生效文件
[root@node100 shell_test]# get_sum 1 2 3 # 调用函数并传参
[root@node100 shell_test]# echo $? # 查看状态