一、shell 介绍
Shell ⼀个命令解释器,它接收应⽤程序/⽤户命令,然后调⽤操作系统内核。 Shell还是⼀个功能强⼤的编程语⾔,易编写、易调试、灵活性强。
二、基本语法定义
2.1. 变量名的定义规则
(1)变量名称可以由字⺟、数字和下划线组成,但是不能以数字开头,环境变量名建议⼤写。
(2)等号两侧不能有空格
(3)在bash中,变量默认类型都是字符串类型,⽆法直接进⾏数值运算。
(4)变量的值如果有空格,需要使⽤双引号或单引号括起来。
2.2. 等号周围没有空格
在 Bash 中,不应该在定义变量时添加额外的空格。
例:name="Zhang"
echo $name输出变量
2.3. 正确地定义数组 :只需要使⽤⼀对括号来包含所有元素。
例: names=("Zhang" "Elon" "Bill")
echo ${arr[1]} 获取数组的值
2.4. 查看所有的变量 set
2.5. 取消变量的设置 unset 变量名
2.6. 将局部环境变量提升为全局 export 变量名
2.7. 正确选择引号
当在 Bash 中声明⼀个变量时,关于引号的使⽤有 3 个可选的⽅案:
- 没有引号
- ⽤单引号
- ⽤双引号
默认情况下,Bash 中的每个值都是⼀个字符串。因此,如果不需要空格,就不需要使⽤任何引号。(同样,它与其他语⾔有些不同,在其他语⾔中,您不能在没有引号的情况下定义字符串) 当需要使⽤引号时,请注意单引号和双引号之间的区别。
- ⼀对单引号内的字符串将始终被解释为它的本身。
- 而双引号内的字符串可以进行解析
#例:
DOG=金毛
D1=’${DOG}是小狗’
D2=”${DOG}是小狗”
echo $D1
输出:${DOG}是小狗
echo $D2
输出:金毛是小狗
2.8. 避免在命令中使⽤反引号
在 Bash 中,可以将命令的结果保存到变量中。有两种可能的⽅法来做到这⼀点:
- variable=`command`
- variable=$(command)
例如,要保存 ls 命令的结果,可以这样写:
file_list=`ls` 或者file_list=$(ls)
但是,这⾥的最佳实践始终是使⽤第⼆种⽅法,尤其是在编写较⻓的脚本时。因为反引号和单引号看起来很相似,有时可能会混淆它们。
2.9. 特殊的变量名
2.9.1. $n
$n(功能描述:n为数字,$0代表该脚本名称,$1-$9代表第⼀到第九个参数,⼗以上的参数需要⽤⼤括号包含,如${10})
sh demo01.sh a b
$0是脚本名字 $1,$2分别表示参数
2.9.2. $#
$# (功能描述:获取所有输⼊参数个数,常⽤于循环)。
2.9.3. $*
$* (功能描述:这个变量代表命令⾏中所有的参数,$*把所有的参数看成⼀个整体)
2.9.4. $@
$@ (功能描述:这个变量也代表命令⾏中所有的参数,不过$@把每个参数区分对待)
2.9.5. $?
$? (功能描述:最后⼀次执⾏的命令的返回状态。如果这个变量的值为0,证明上⼀个命令正确执⾏;如果这个变量的值为⾮0(具体是哪个数,由命令⾃⼰来决定),则证明上⼀个命令执⾏不正确了。)
三、运算符
3.1 算数运算符
(1)“ $((运算式))” 或“ $[运算式]”
(2)expr + , - , \*, /, % 加,减,乘,除,取余
注意:expr运算符间要有空格
例:expr 3 + 2
3.2 逻辑运算符
格式:[ 条件 ] 注意:[] ⾥⾯前后必须要有空格
结果:0 表示真 ⾮0表示假
(1)两个整数之间⽐较
- = 字符串⽐较
- -lt ⼩于(less than)
- -le ⼩于等于(less equal)
- -eq 等于(equal)
- -ne 不等于(Not equal)
- -gt ⼤于(greater than)
- -ge ⼤于等于(greater equal)
#例:
[ 9 -lt 10 ]
echo $?
输出:0 表示真
(2)按照⽂件权限进⾏判断
- -r 有读的权限(read)
- -w 有写的权限(write)
- -x 有执⾏的权限(execute)
#例:
[ -r demo01.sh ]
echo $?
(3)按照⽂件类型进⾏判断
- -f ⽂件存在并且是⼀个常规的⽂件(file)
- -e ⽂件存在(existence)
- -d ⽂件存在并是⼀个⽬录(directory)
(4)多条件判断(&& 表示前⼀条命令执⾏成功时,才执⾏后⼀条命令,|| 表示上⼀条命令执⾏失败后,才执⾏下⼀条命令)
#例:
[ 9 -lt 10 ] && echo 对
输出 对
[ 9 -gt 10 ] && echo 对
无输出
四、 正则表达式
正则表达式使⽤单个字符串来描述、匹配⼀系列符合某个语法规则的字符串。 在很多⽂本编辑器⾥,正则表达式通常被⽤来检索、替换那些符合某个模式的⽂本。 在 Linux 中, grep,sed, awk 等⽂本处理⼯具都⽀持通过正则表达式进⾏模式匹配。
4.1. 常规匹配
例如下⾯的命令,会对/etc/passwd的每⾏内容进⾏匹配,将含有root的⾏输出,输出内容红⾊的部分即为匹配的内容
cat /etc/passwd | grep root
4.2. 常⽤的特殊字符串
4.2.1. 特殊字符:^
^匹配⼀⾏的开头,如下,会匹配/etc/passwd中以root开头的⾏
cat /etc/passwd | grep ^root
4.2.2. 特殊字符:$
$匹配⼀⾏的结尾,如下,会匹配出/etc/passwd中以bash结尾的⾏
cat /etc/passwd | grep bash$
4.2.3. 特殊字符:.
.匹配⼀个任意字符,如下,可以匹配含有四个字符,其中第1个字符是r,第4个字符是t的⾏,中间两个 可以是任意字符
cat /etc/passwd | grep r..t
4.2.4. 特殊字符:*
*不单独使⽤,他和上⼀个字符连⽤,表示匹配上⼀个字符0次或多次,如下,可以匹配第1个字符是r, 最后1个字符是t,中间可以包含任意数量的o
cat /etc/passwd | grep ro*t
4.2.5. 字符区间(中括号):[]
[]表示匹配某个范围内的⼀个字符,例如
[6,8] 匹配6或者8
[0-9] 匹配1个0-9的数字
[0-9]* 匹配任意⻓度的数字字符串
[a-z] 匹配1个a-z之间的字符
[a-z]* 匹配任意⻓度的字⺟字符串
[a-ze-f] 匹配a-z或者e-f之间的任意⼀个字符
cat /etc/passwd | grep "[a-z]*"
4.2.6. 特殊字符:\
\表示转义,并不会单独使⽤,由于所有特殊字符都有其特定的匹配模式,当匹配某⼀特殊字符本身时 (例如,我想找出所有包含‘ $’ 的⾏),就会碰到困难,此时就要将转义字符和特殊字符连⽤,来表示特殊字符本身,例如
echo '123$54$5432' | grep '\$'
注:不能用双引号 因为双引号会转义掉$
扩展的正则表达式 :有些语⾔中⽀持正则表达式的扩展语法,需要添加-E选项,否则⽆法识别这种语法。
⽐如下⾯2⾏,匹配a-z中的任意字符2或者3次
echo "ab,cdre" | grep -E "[a-z]{2,3}"
五、条件选择、判断、循环
5.1. 条件选择 if
注意事项:
(1)[ 条件判断式 ],中括号和条件判断式之间必须有空格
(2)if后要有空格
#语法格式
if 判断条件 1 ; then
条件为真的分⽀代码
elif 判断条件 2 ; then
条件为真的分⽀代码
elif 判断条件 3 ; then
条件为真的分⽀代码
else
以上条件都为假的分⽀代码
fi
#例:
if [ $1 -lt 16 ]
then
echo "娃还小"
else
echo "娃长大了"
fi
5.2. 条件判断 case
#语法格式
case $name in
PART1)
cmd
;;
PART2)
cmd
;;
*)
cmd
;;
esac
#例:
case $1 in
"上午")
echo "火锅"
echo "烤肉"
;;
"中午")
echo "3碗大米饭"
echo "6个纯瘦夹馍"
;;
"晚上")
echo "粥"
echo "小甜水"
;;
*)
echo "请填写正确的时间"
;;
esac
注意事项:
1) case⾏尾必须为单词“ in” ,每⼀个模式匹配必须以右括号“ )” 结束。
2) 双分号“ ;; ” 表示命令序列结束,相当于java中的break。
3) 最后的“ *)” 表示默认模式,相当于java中的default。
5.3. 循环(四种)
5.3.1. for
#语法格式
# ⽅式⼀
for name in 列表 ;do
循环体
done
# ⽅式⼆ 类似于 C 语⾔⻛格的语法
for (( 初始值 ; 条件表达式 ; 变量改变 )) ;do
cmd
done
#例:
#方式一
for j in $*
do
echo $j
done
#方式二
s=0
for((i=0;i<=100;i++))
do
s=$[$s+$i]
done
echo $s
#对$* 和 $@ 做对⽐:
for j in "$*"
do
echo $j
done
for j in "$@"
do
echo $j
done
$*最终会被" "解析为一个连续的字符串只有一个元素
$@最终会被" "解析为一个数组每个元素都是传入的参数
sh demo05.sh aa bb cc
输出结果如下:
aa bb cc
aa
bb
cc
5.3.2. while
#语法格式
while 循环控制条件 ;do
循环
done
循环控制条件;进⼊循环之前,先做⼀次判断;每⼀次循环之后会再次做判断;条件为“ 执⾏⼀次循环;直到条件测试状态为“ false ” 终⽌循环
#例:
num=$1
s=0
while [ $num -ge 0 ]
do
s=$[$num+$s]
num=$[$num-1]
done
echo $s
5.3.3. until 循环
#语法格式
unitl 循环条件 ;do
循环
done
进⼊条件:循环条件为true ;退出条件:循环条件为false;刚好和while相反,所以不常⽤,⽤while就 ⾏。
#例:
num=$1
s=0
until [ $num -eq 0 ]
do
s=$[$num+$s]
num=$[$num-1]
done
echo $s
5.3.4. select 循环与菜单
#语法格式
select variable in list
do
循环体命令
done
① select 循环主要⽤于创建菜单,按数字顺序排列的示菜单项将显示在标准错误上,并显示PS3 提示 符,等待⽤户输⼊
② ⽤户输⼊菜单列表中的某个数字,执⾏相应的命令
③ ⽤户输⼊被保存在内置变量 REPLY 中
④ select 是个⽆限循环,因此要记住⽤ break 命令退出循环,或⽤ exit 按 命令终⽌脚本。也可以按 ctrl+c退出循环
⑤ select 和 经常和 case 联合使⽤
⑥ 与for循环类似,可以省略 in list, 此时使⽤位置参量
#例:
PS3=" 请输⼊你要选择的序号 : "
select menu in ⽶饭 扯⾯ 包⼦ 稀饭 退出
do
case $REPLY in
1|4)
echo "$menu 价格是 15"
;;
2|3)
echo "$menu 价格是 20"
;;
5)
break
;;
*)
echo " 输入错误! "
esac
done
分析: PS3 是 select 的提示符,⾃动⽣成菜单,选择5 break 退出循环。
5.4. 循环⾥的⼀些⽤法
5.4.1. 循环控制语句
语法:
continue :提前结束第N层的本轮循环,⽽直接进⼊下⼀轮判断;最内层为第1层
break :提前结束第N层循环,最内侧为第1层
#例:
while CONDTITON1; do
CMD1
if CONDITION2; then
continue / break
fi
CMD2
done
六、read 读取控制台输⼊
6.1. 语法
read(选项)(参数)
选项:
-p:指定读取值时的提示符;
-t:指定读取值时等待的时间(秒)。
参数:
变量:指定读取值的变量名
#脚本:
read -p "请输入你的名字" -t 5 username
echo $username
sh demo01.sh
#脚本:
read -p "请输入第一个数:" num1
read -p "请输入第二个数:" num2
echo "$num1 加上 $num2 的结束是 $[$num1+$num2]"
七、 ⾃定义函数
# 语法:
[ function ] funname[()]
{
Action;
[return int;]
}
Funname
#例:
function func1()
{
read -p "请输入第一个数:" num1
read -p "请输入第二个数:" num2
echo "$num1 加上 $num2 的结束是 $[$num1+$num2]"
}
func1
注意:
(1)必须在调⽤函数地⽅之前,先声明函数,shell脚本是逐⾏运⾏。不会像其它语⾔⼀样先编译。
(2)函数返回值,只能通过$?系统变量获得,可以显示加:return返回,如果不加,将以最后⼀ 条命令运⾏结果,作为返回值。return后跟数值n(0-255)
#练习:编写⼀个函数来计算输⼊的是不是⼀个质数
function func2()
{
isok=1
for(( i=2 ; i<$1 ; i++))
do
if [ $[ $1 % $i] -eq 0 ]
then
isok=0
break
fi
done
if [ $isok -eq 1 ]
then
echo "$1 是一个质数"
else
echo "$1 不是一个质数"
fi
}
read -p "请输入一个数" num
func2 $num