目录:
1.解释器
2.shell脚本
脚本执行
变量定义
特殊变量($开头的变量)
从命令行输入变量(read方法)
变量扩展(判断变量不存在使用默认值、字符串测量截取替换)
条件测试(文件测试、字符串、数值、条件符号&|)
控制语句(if else、case、for等)
函数

正文:
一.解释器
linux提供shell解释器有多种
/bin/sh
/bin/bash
/sbin/nologin
/bin/dash
/bin/tcsh
/bin/csh
其中sh和bash是默认的解释器,sh是bash的软链接,本质上是一个东西

[root@master2 bin]# ll /bin/ | grep bash
-rwxr-xr-x    1 root root     964536 Nov 25  2021 bash
lrwxrwxrwx    1 root root          4 Sep 14  2022 sh -> bash

echo $SHELL 可以查询当前shell解释器

二.shell脚本
脚本以 #!/bin/bash 开头指定解释器

1.脚本执行:
使用sh或者bash + 脚本的路径
sh helloworld.sh 不用赋予脚本+x权限

使用脚本的路径(需要可执行权限)
./helloworld.sh

2.变量定义:变量=值
(1)变量名称可以由字母、数字和下划线组成,但是不能以数字开头,环境变量名建议大写。
(2)等号两侧不能有空格
(3)在bash中,变量默认类型都是字符串类型,无法直接进行数值运算。
(4)变量的值如果有空格,需要使用双引号或单引号括起来。
(5)export变量可以将变量提升为全局变量,export MYNAME=”my name is kevin”
双引号可以解析变量的值,单引号不可以,会将单引号中的内容作为一个字符串
上述变量的定义是临时的,针对一次shell,下次打开就没有了,如果想要永久的变量,需要修改/etc/profile或用户目录的.bash_profile,前者是整个系统的,后者是单个用户的

C=1+2
echo $C
结果:1+2
D=“I love banzhang”
echo $D
结果:I love banzhang

3.特殊变量

$n
$0表示脚本名称,$1-9表示第一到第九个参数,十以上的参数需要大括号包含,${10}

#!/bin/bash
echo "$0 $1 $2"

[root@master2]# sh testshell.sh x sss
testshell.sh x sss

$#
表示参数的个数
$*
表示命令行中所有的参数,所有的参数看成一个整体
$@
表示命令行中所有的参数,每个参数都区分对待

例子:
[root@master2]# cat testshell.sh
#!/bin/bash
echo "$0 $1 $2"
echo "$#"
echo "$*"
echo "$@"

[root@master2]# sh testshell.sh x  sss   ddddd
testshell.sh x sss
3
x sss ddddd
x sss ddddd

$?
最后一次执行的命令的返回状态。如果这个变量的值为0,证明上一个命令正确执行
如果这个变量的值为非0(具体是哪个数,由命令自己来决定),则证明上一个命令执行不正确
[root@master2]# echo $?
0

$$
表示当前进程号
[root@master2 zykfile]# cat testshell.sh
#!/bin/bash
echo "$$"
[root@master2 zykfile]# sh testshell.sh
21866

特殊符号:

""双引号可以解析变量的值
''单引号不可以解析变量的值,会将单引号中的内容作为一个字符串
``反引号中的内容是一条命令,可以执行
$()和``的效果一样,可以执行的命令
\转义字符,需要配合-e使用,echo -e "xx\nx"
()括起来子shell,其中的变量赋值不会影响到当前shell的变量
{}当前shell,会影响当前shell的变量

4.从命令行输入变量:
使用read关键字,同时定义了变量。-p可以输出描述

[root@master2]# cat testshell.sh
#!/bin/bash
echo "$0 $1 $2"
read -p "输入:" num
echo "$num"

[root@master2]# sh testshell.sh x  sss   ddddd
testshell.sh x sss
输入:123456
123456

read多个输入参数

[root@master2]# cat testshell.sh
#!/bin/bash
echo "$0 $1 $2"
read -p "输入:" num num1
echo "$num $num1"

[root@master2]# sh testshell.sh x  sss   ddddd
testshell.sh x sss
输入:123 456
123 456

5.变量扩展

1.判断变量是否存在,不存在的话使用默认值,格式为:${num:-100}
[root@master2]# cat testshell.sh
#!/bin/bash
echo "${num:-100}"
num=500
echo $num
[root@master2]# sh testshell.sh
100
500

2.字符串操作
测量字符串长度:#字符串
从下标处截取字符:字符串:下标
从下标处截取n个字符:字符串:下标:n

[root@master2]# cat testshell.sh
#!/bin/bash
string="123456789qwertyuiop"
echo "${#string}"
echo ${string:3}
echo ${string:3:6}

[root@master2]# sh testshell.sh
19
456789qwertyuiop
456789

3.字符串替换输出
输出的时候替换第一个出现的字符:字符串/aa/bb
[root@master2]# cat testshell.sh
#!/bin/bash
string="123456789qwertyuiop"
echo ${string/qwer/asdf}
echo $string
[root@master2]# sh testshell.sh
123456789asdftyuiop
123456789qwertyuiop

输出的时候替换所有字符:字符串//aa/bb
[root@master2]# cat testshell.sh
#!/bin/bash
string="qwertyuiopqwertyuiop"
echo ${string//qwer/asdf}
echo $string
[root@master2]# sh testshell.sh
asdftyuiopasdftyuiop
qwertyuiopqwertyuiop

6.条件测试,用于测试字符串、文件状态等
格式为:test condition 或[ condition ],方括号的两边需要加一个空格。任何逻辑操作符号和字符之间都需要加一个空格!!!

(1)文件测试:

-e 是否存在
-d 是目录
-f 是文件
-r 可读
-w 可写
-x 可执行
-L 符号链接
-c 字符设备
-b 块设备
-s 文件非空,$?返回1表示文件空,返回0表示文件不空

举例:[ -e /root/zzzz ]

[root@master2]# cat testshell.sh
#!/bin/bash
read file
[ -e $file ]
echo $?
[root@master2]# sh testshell.sh
/root/zzz
0
[root@master2]# sh testshell.sh
/root/zzzzz
1

(2)字符串测试

= 字符串相等
!= 字符串不相等
-z 空串
-n 非空串

[root@master2]# cat testshell.sh
#!/bin/bash
tstring="asdfghjkl"
astring="asdfghjkl"

[ -z $tstring ]
echo $?

[ -n $tstring ]
echo $?

[ $tstring = $astring ]
echo $?

[ $tstring != $astring ]
echo $?


[root@master2]# sh testshell.sh
1
0
0
1

(3)数值测试

-eq 相等 equal
-ne 不相等 not e
-gt 大于 greater than
-ge 大于等于 greater equal
-lt 小于 less than
-le 小于等于 less equal

[root@master2]# cat testshell.sh
#!/bin/bash
a=1
b=1
c=2
d="-1"

[ $a -eq $b ]
echo $?

[ $a -ne $b ]
echo $?

[ $a -ge $b ]
echo $?

[ $a -gt $c ]
echo $?

[ $a -gt $d ]
echo $?

[root@master2]# sh testshell.sh
0
1
0
1
0

(4)符合语句测试

&& 前面语句如果执行成功,才执行后面语句

[root@master2]# cat testshell.sh
#!/bin/bash
[ "aaa" = "aaa" ] && [ "a" = "a" ] &&  echo "success"

[root@master2]# sh testshell.sh
success

|| 前面语句执行失败,才执行后面语句

[root@master2]# cat testshell.sh
#!/bin/bash
[ "aaa" = "aaa" ] && [ "aa" = "aaia" ] ||  echo "success"

[root@master2]# sh testshell.sh
success

-a 前后条件同时成立
-o 前后条件任一成立
! 不成立

[root@master2]# cat testshell.sh
#!/bin/bash
[ "aaa" = "aaa" -a "aaa" = "aaa" ] && echo "success"

[root@master2]# sh testshell.sh
success


[root@master2 zykfile]# cat testshell.sh
#!/bin/bash
[ "aaa" = "aaa" -o "aa" = "aaa" ] && echo "success"

[root@master2 zykfile]# sh testshell.sh
success

[root@master2 zykfile]# cat testshell.sh
#!/bin/bash
[ ! "aaaa" = "aaa" ] && echo "success"

[root@master2 zykfile]# sh testshell.sh
success

7.控制语句
(1)if语句

格式一:
if [条件1]; then
    
else
    
fi

格式二:
if [条件1]; then
    
elif [条件2];then

else
    
fi

举例
如果目录不存在,则创建目录后创建文件,如果目录存在,直接创建文件

#!/bin/bash
dir="/root/zykfile/shellt"

if [ -e $dir ] ; then
  echo "目录存在"
  cd $dir
  touch zykzyk.c
else
  echo "目录不存在"
  mkdir $dir
  cd $dir
  touch zykzyk.c
fi
#!/bin/bash
dir="/root/zykfile/shellt"

if [ -e $dir ] ; then
  echo "目录存在"
  cd $dir
  touch zykzyk.c
elif [ "a" = "a" ] ; then
  echo "目录不存在"
  mkdir $dir
  cd $dir
  touch zykzyk.c
fi

(2)case语句

格式:其中case * 表示default,;;表示break
case $变量 in
  变量名称1)
    语句
    ;;
  变量名称2)
    语句
    ;;
  *)
    语句
    ;;
esac

举例,根据输入进行输出,可以模糊匹配

[root@master2]# cat testshell.sh
#!/bin/bash
read  str
case $str in
   a)
    echo "aaa"
    ;;
  "b" | b* | B*)
    echo "bbb"
    ;;
  *)
    echo "other"
    ;;
esac
[root@master2]# sh testshell.sh
a
aaa
[root@master2]# sh testshell.sh
b
bbb
[root@master2]# sh testshell.sh
baaaaa
bbb
[root@master2]# sh testshell.sh
Bjjj
bbb
[root@master2]# sh testshell.sh
aaaa
other

(3)for语句

格式一:和java类似
for (( 初始值;限制值;步阶 ))
do
  语句
done

格式二:第一次循环,$var内容是con1,以此类推
for var in con1 con2 con3
do
  语句
done

举例,循环n次
declare是内建命令,declare -i s,代表将s变量当作int类型计算
获取当前目录文件,循环输出文件类型

[root@master2]# cat testshell.sh
#!/bin/bash

declare -i sum
declare -i i

for (( i=0; i<=10; i++ ))
do
  sum=$sum+$i;
  echo $sum
done
[root@master2]# sh testshell.sh
0
1
3
6
10
15
21
28
36
45
55

[root@master2]# cat testshell.sh
#!/bin/bash

declare -i sum
declare -i i

for i in 1 2 3 4
do
  sum=$sum+$i;
  echo $sum
done
[root@master2]# sh testshell.sh
1
3
6
10

[root@master2]# cat testshell.sh
#!/bin/bash

for name in `ls`
do
  if [ -d $name ]; then
    echo "$name是文件夹"
  elif [ -f $name ]; then
    echo "$name是文件"
  fi
done
[root@master2]# sh testshell.sh
xxx是文件
server.crt是文件
server.csr是文件
server.key是文件
shellt是文件夹

(4)while语句,条件满足时不断循环

格式
while [ condition ]
  do
    代码
  done

举例,字符串拼接,直到while条件满足

[root@master2]# cat testshell.sh
#!/bin/bash

s=""
while [ "$s" != "sss" ]
  do
    s="${s}s"
  done
echo $s

[root@master2]# sh testshell.sh
sss

可以使用while true,表示无限循环

(5)until语句,条件满足时跳出循环

格式
until [ condition ]
  do
    代码
  done

举例,字符串拼接,满足条件时跳出循环

[root@master2]# cat testshell.sh
#!/bin/bash

s=""
until [ "$s" = "sss" ]
  do
    s="${s}s"
  done
echo $s

[root@master2]# sh testshell.sh
sss

(6)break,continue
和java用法一样,用于跳出循环

[root@master2]# cat testshell.sh
#!/bin/bash

s=""
until [ "$s" = "sss" ]
  do
    s="${s}s"
    if [ "$s" = "ss" ]; then
      break
    fi
  done
echo $s

[root@master2]# sh testshell.sh
ss

8.函数
函数在使用前必须定义,放在脚本的开始部分

格式一
函数名() {
  代码
}

格式二
function 函数名() {
  代码
}

使用函数时:函数名 param1 param2
和脚本中使用特殊变量$1 $2一样,函数中也可以这样使用入参
函数可以使用return 提前结束并带有返回值

[root@master2]# cat testshell.sh
#!/bin/bash

function maxnum (){
  if [ $1 -gt $2 ]; then
    return $1
  else
    return $2
  fi
}

read data1 data2
maxnum $data1 $data2
echo "max is $?"

[root@master2]# sh testshell.sh
12 13
max is 13

函数的返回:
1.return返回
return返回只支持数字0-255,超过255则从0开始计算。通常返回0作为成功,1表示失败,状态码可以自定义
如果函数中只写一个return,表示return 0,两个是等价的。如果函数中没有return语句,则使用默认的退出状态,即最后一条命令的退出状态码
获取函数结果,可以用$?

2.echo返回
没有return时,函数以最后一条命令的运行结果作为返回值,因此可以在最后一行使用echo ""作为返回值,如果有多条echo,也只会以最后一个echo为返回值
获取函数结果,可以赋值结果给变量,string=$(get_string)

3.exit
exit是一个系统调用级别的函数,在进程层面工作,表示进程的退出
exit 0表示脚本执行成功
exit 其他数字表示脚本执行失败,数字可以自定义
获取脚本执行成功失败可以用$?
return是函数级别的退出,本身是关键字,表示退出函数

函数导入
一个脚本可以引用另一个脚本
在脚本开始编写:source xxx.sh,函数就可以直接用函数名调用
引用后会将另一个脚本中的命令也都执行掉,所以另一个脚本中最好只定义函数,不编写命令