shell脚本文件编写

shell脚本文件编写

1.shell脚本的基本格式

脚本文件的第一行必须是#! /bin/bash,后面再加上要执行的指令。在脚本文件中代码的注释使用#

#! /bin/sh
#这是第一个脚本文件
date  #输出系统当前时间 格式如:2019年 12月 27日 星期五 23:28:07 CST
echo "hello world." #echo在终端输出内容

多行注释可以使用如下格式:

:<<EOF
注释内容...
注释内容...
注释内容...
EOF

上面代码中的EOF可以使用任意字符替换,比如abc等,但是使用单引号和`两个。例如:

#!/bin/sh
#这里是单行注释,系统不会执行
:<<``
这里是多行注释,系统也不会执行
这里是多行注释,系统也不会执行
这里是多行注释,系统也不会执行
这里是多行注释,系统也不会执行
``

:<<''
这里也是多行注释,系统也不会执行
这里也是多行注释,系统也不会执行
这里也是多行注释,系统也不会执行
这里也是多行注释,系统也不会执行
''

:<<a
这里也是多行注释,系统也不会执行
这里也是多行注释,系统也不会执行
这里也是多行注释,系统也不会执行
这里也是多行注释,系统也不会执行
a

:<<#
这里也是多行注释,系统也不会执行
这里也是多行注释,系统也不会执行
这里也是多行注释,系统也不会执行
这里也是多行注释,系统也不会执行
#

2.shell/Linux的基本指令

Linux中基本指令实在是太多了,要想通过看一片博客就掌握是不可能的,还是得自己平时多多使用Linux,慢慢积累总结才能收获最多。如果你真的想系统学习一下Linux中的基本指令,这里推荐几个参考网站:

Linux命令大全|菜鸟教程

Linux命令大全(手册)

55 个 Linux 教程和练手项目列表

Linux命令大全(手册)

3.shell脚本基本语法

3.1 变量

变量的命名方式和c语言一样。使用一个定义过的变量只要在变量名前面加美元符号即可,变量名外面的花括号是可选的,加花括号是为了帮助解释器识别变量的边界。

脚本中的变量都是字符串,一个变量可以处于已定义和未定义两种状态,已定义的变量可以有值也可以为空。

定义变量时不要有空格,要获取一个变量的值的时候,用${}把变量名包起来,叫做变量扩展。扩展得到的变量可以在脚本中使用。

示例:

a='hello'
echo $a

结果为:

hello

注意:

  • 切记,在定义变量的时候不要习惯性的在等号两边加空格,一旦加了空格,系统会把a识别成一个指令,会报系统找不到a指令的错误

    例如:

a  =  hello
echo ${a}

结果为:

a:未找到命令
  • 变量加不加引号都是一样的效果

  • 在${var}后面还可以拼接其他字符串,相当于拼接字符串

    例如:

    a=hello
    echo ${a}_world
    

    结果为:

    hello_world
    

用$()可以获取指令的输出当做变量

例如:

a=hello
#将echo输出的a的内容当做变量赋值给变量b
b=$(echo $a)
#变量输出的是a的内容
echo $b

结果为:

hello
  • 可以将变量设置为只读,例如:

    a=hello
    readonly a
    a=world
    

    系统会提示变量为只读,结果如下:

    bash: a: 只读变量
    
  • 删除变量 unset

    a=hello
    unset a
    echo a
    

    这里输出为空

  • 字符串可以用单引号,也可以用双引号,可以不用引号。单双引号的区别为:

    1.单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的

    2.单引号字符串中不能出现单独一个单引号(对单引号使用转义字符也不行),但可以成对出现,作为字符串拼接使用。

    3.双引号里面可以有变量

    4.双引号里面可以出现转义字符

    例如

    a="hello"
    #使用双引号拼接
    b1="${a},world!"
    b2=""$a",world!"
    echo $b1 $b2
    #使用单引号拼接
    b3=''$a',world!'
    b4='${a},world!'
    echo $b3 $b4
    

    结果为:

    hello,world! hello,world!
    hello,world! ${a},world!
    

3.2 数组

bash支持一维数组,但不支持多维数组,并且没有限定数组的大小。

类似于c语言,数组元素的下标由0开始编号。获取数组中的元素要利用下标,下标可以是整数或算术表达式,其值应大于或等于0.

3.2.1数组的定义

在shell中,用括号来表示数组,数组元素用“空格”符号分隔开,定义数组的一般形式为:

array_name=(value0 value1 value2 value3 value4)

或者

array_name=(
value0
value1
value2
value3
value4
)

还可以单独定义数组的各个元素

array_name[0]=value0
array_name[1]=value1
array_name[n]=valuen

可以使用不连续的下标,而且下标的范围没有限制。

示例:

3.2.2 读取数组

读取数组的一般形式为:

#读取数组中第n+1个元素
${array_name[n]}

使用@符号可以获取数组中的所有元素

echo ${array_name[@]}

3.2.3 获取数组的长度

获取数组的长度的方法与获取字符串长度的方法相同,格式为:

#获取数组元素的个数
length=${#array_name[@]}
#或者
length=${#array_name[*]}
#取得数组单个元素的长度
length=${#array_name[n]}

数组综合示例:

#定义数组
array=(1 2 3 4 5 6)
#单独定义数组元素,并使用不连续的数组下标
array[8]=7
#获取单个元素
echo ${array[8]}
#获取没有不存在的下标的值为空
echo ${array[6]}
#获取所有元素
echo ${array[@]}
#获取数组的长度
length=${#array[@]}

结果为:

7

1 2 3 4 5 6 7
7

3.3 条件赋值

  1. v a r : − s t r i n g 和 {var:-string}和var:string{var:=string}

    若变量var为空或者没有定义,则用string作为${var:-string}的值,否则用变量var的展开值,但是虽然${var:-string}整体的值是string的值,但是变量var的值还是为空或者未定义,并没有改变变量var${var:=string}就会改变变量var的值,只要var为空,就会把string的值赋值给var

    例如:

    #直接输出变量a的值,因为没有定义a变量,因此这里书出的内容应该为空
    echo $a
    #使用${var:=string}格式
    echo ${a:-hello} #这里输出的是hello,但是a变量仍然是为定义
    #因此这里输出的a变量的值依然是空
    echo $a
    #使用${var:=string}这个格式
    echo ${a:=abc}
    #使用${var:=string}格式
    echo ${a:-hello} #因为这里a变量已经有了值,因此直接使用a变量的值输出的应该是abc
    
  2. ${var:+string}

    规则和上面${var:-string}完全相反,当var不是空的时候值为string,若为空,则是var的值。

    #直接使用${var:+string}
    echo ${a:abc} #a未定义,因此这里输出的是a的值
    #给变量赋值
    a=hello
    #再次使用${var:+string}
    echo ${a:abc} #因为a变量已经有了值,因此这里输出的是a的值
    
  3. ${var:?string}

    若变量var的值不为空,则用变量var的值作为展开值,否则将string输出到标准错误中,并从脚本中退出

    #给变量赋初值
    a=hello
    #使用${var:?string}
    echo ${a:?aab}#因为a有值,因此这里输出的应该是a的值hello
    #直接对变量b使用${var:?stirng}
    echo ${b:?abc}#这里b没有定义,值为空,因此输出应该是标准错误bash: b: abc
    
  4. $((C表达式)

    这种计算是符合c语言的运算符,也就是只要符合c的运算符都可以用在上面表达式里面。

    注意:

    • 这种扩展计算是整数类型的计算,不支持浮点数核字符串。如果是逻辑运算,表达式为真则为1,否则为0
    • 上面表达式必须是要用括号把表达式包起来
    #给变量a赋初值10
    a=10
    #如果变量a大于0,输出1,否则输出0
    echo $((a>0?1:0))
    #这里输出应该为1
    
  5. 模式匹配替换结构

    表达式功能
    ${var%pattern}从右边最短匹配
    ${var%%pattern}从右边最长匹配
    ${var#pattern}从左边最短匹配
    ${var##pattern}从左边最长匹配

    注意:输出的内容是var去掉pattern匹配到的呢部分北荣剩下的内容

    例如:

    a=a.tar.gz
    #查找a中去掉满足匹配内容最长字符串后剩下的内容
    #这里的输出应该为a.tar
    echo ${a##*.}
    echo ${a%%.*}
    

    6.字符串替换:v a r / s t r 1 / s t r 2 和 {var/str1/str2}和var/str1/str2{var//str1/str2}

    表达式功能
    ${var/str1/str2}将var变量中的第一个str1子字符串替换为字符串str2
    ${var//str1/str2}将var变量中所有的str1子字符串全部替换为str2

    示例:

    a=a.tar.gz
    #将a字符串中的第一个'a'替换为'b'
    #输出应该为b.tar.gz
    echo ${a/a/b}
    #将字符串中所有'.'替换为'/'
    #输出应该为b/tar/gz
    echo ${a//.//}
    

    7.获取字符串长度:${#var}

    示例:

    a=abcdefghijklmn
    #获取a变量中字符串长度
    echo ${#a}
    

    结果:

    14
    

3.4 流程控制

3.4.1 if-then语句

if command1;then
	commands
elif command2;then
	commands
else
	commands
fi

if语句会执行后面的命令,如果命令退出状态码是0,则是正常退出,位于then部分的命令就会执行,否则else部分的命令会执行。

参考博客:

shell脚本语法

3.5 Shell传递参数

我们可以在执行Shell脚本时,向脚本传递参数,脚本内获取参数的格式为:$n.n表示一个数字,1

为执行脚本的第一个参数,2为执行脚本的第二个参数,以此类推…

需要注意的是:$0为执行文件的文件名,是默认传递的

示例:

创建一个test.sh文件,文件内容为:

#! /bin/sh
echo "执行脚本文件为:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";

在文件所在目录打开终端,并输入以下命令:

chmod +x test.sh
./test.sh hello world szq

结果为:

执行脚本文件为:./test.sh
第一个参数为:hello
第二个参数为:world
第三个参数为:szq

另外,还有几个特殊字符用来处理参数:

参数处理说明
$#参数的个数
$*以一个单字符串显示所有向脚本传递的参数
$$脚本运行的当前进程的id号
$!后台运行的最后一个进程的id号
$@与$*相同,但是使用时加引号,并在引号中返回每个参数
$-显示Shell使用的当前选项,与set命令功能相同
$?显示最后命令的退出状态,0表示没有错误,其他任何值表明有错误

示例

#! /bin/sh
echo "执行脚本文件为:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";
echo "参数个数为:$#";
echo "传递的参数作为一个字符串显示:$*";
echo "脚本运行的当前进程的id号:$$";
echo "后台运行的最后一个进程的id号:$!";
echo "显示Shell使用的当前选项:$-";
echo "显示最后命令的退出状态,0表示没有错误,其他任何值表明有错误:$?";

结果为:

执行脚本文件为:./test.sh
第一个参数为:hello
第二个参数为:world
第三个参数为:szq
参数个数为:3
传递的参数作为一个字符串显示:hello world szq
脚本运行的当前进程的id号:6578
后台运行的最后一个进程的id号:
显示Shell使用的当前选项:
显示最后命令的退出状态,0表示没有错误,其他任何值表明有错误:0

∗ 与 *与@的区别:

  • 相同点:都是引用所有参数。
  • 不同点:只有在双引号中体现出来。$*相当于将输入的所有参数当成一个字符串处理,而$@将各个参数分开处理。

例如:

#!/bin/sh
echo 'test $*'
for ele in "$*";do
echo $ele;
done

echo 'test $@'
for ele in "$@";do
echo $ele;
done

执行下面命令:

chmod +x test.sh
./test.sh hello world szq

结果为:

test $*
hello world szq
test $@
hello
world
szq

3.6 基本运算符

3.6.1 算术运算符

下表列出了常用的算术运算符,假定变量a为10,变量b为20:

运算符说明举例
+加法`expr $a + $b` 结果为30
-减法`expr $a - $b` 结果为-10
*乘法`expr $a * $b` 结果为200
/出发`expr $b / $a` 结果为2
%取余`expr $b % $a` 结果为0
=赋值a = $b 将变量b的值赋值给a
==相等,用于比较两个数字是否相同,相同则返回true[$a == $b] 返回false
!=不相等,用于比较两个数字,不相同则返回true[$a != $b] 返回true

注意:

  • 原生bash不支持简单的数学运算,但是可以通过其他命令来实现,例如awk和expr,expr最常用。
  • 表达式和运算符之间要有空格,例如2+2是不对的,必须写成2 + 2
  • 完整的表达式要被``包含,注意这个字符不是常用的单引号,在ESC下面
  • 乘法前边必须加反斜杠才能实现乘法运算

例如

#!/bin/sh
a=10
b=20
#加法
val=`expr $a + $b`
echo "a + b = $val"
#减法
val=`expr $a - $b`
echo "a - b = $val"
#乘法
val=`expr $a \* $b`
echo "a * b = $val"
#除法
val=`expr $b / $a`
echo "b / a = $val"
#取余运算
val=`expr $b % $a`
echo "b % a = $val"
#赋值
a=$b
echo "a = $a"
#判断a和b是否相等,这里有可能出错,可以将==换成-eq
if [$a == $b]
then
	echo "a等于b"
fi
#判断a和b是否不相等,这里也可能出错,可以将!=换成-ne
if [$a != $b]
then 
	echo "a不等于b"
fi

结果为:

a + b = 30
a - b = -10
a * b = 200
b / a = 2
b % a = 0
a = 20
a等于b

3.6.2 关系运算符

关系运算符只支持数字,不支持字符串,除非字符串的值为数字。

下表列出了常用的关系运算符,假定变量a的值为10,变量b为20

运算符说明举例
-eq检测两个数是否相等,相等返回true[ $a -eq $b ]返回false
-ne检测两个数是否不相等,不相等返回true[ $a -ne $b ] 返回true
-gt检测左边的数是否大于右边的,如果是,返回true[ $a -gt $b] 返回false
-lt检测左边的数是否小于右边的数,如果是,返回true[ $a -lt $b ]返回true
-ge检测左边的数是否大于等于右边的数,如果是返回true[ $a -ge $b ] 返回false
-le检测左边的数是否小于等于右边的数,如果是,返回true[ $a -le $b ] 返回true

示例:

#!/bin/sh
a=10
b=20
#判断是否相等
if [ $a -eq $b ]
then 
	echo "a等于b"
fi
#判断是否不相等
if [ $a -ne $b ]
then 
	echo "a不等于b"
fi
#判断a是否大于b
if [ $a -gt $b ]
then 
	echo "a大于b"
fi
#判断a是否小于b
if [ $a -lt $b ]
then
	echo "a小于b"
fi
#判断a是否大于等于b
if [ $a -ge $b ]
then 
	echo "a大于等于b"
fi
#判断a是否小于等于b
if [ $a -le $b ]
then 
echo "a小于等于b"
fi

结果为:

a不等于b
a小于b
a小于等于b

注意:

  • []内部开始和结尾都需要有空格,即[$a - eq $b]是不对的,只能[ $a -eq $b ]

3.6.3 布尔运算符

下表列出了常用的布尔运算符,假定变量a为10,变量b为20

运算符说明举例
!非运算,表达式为true时返回false,否则返回true[ !false ]返回true
-o或运算,有一个表达式为true时返回true[ $a -lt 20 -o $b -gt 100] 返回true
-a与运算,表达式都为true时返回true[ $a -lt 20 -a $b -gt 100] 返回false

示例

#!/bin/sh
a=10
b=20

#测试与运算
if [ $a -lt 100 -a $b -gt 15 ]
then 
	echo "a小于100并且b大于15,返回true"
else
	echo "a小于100并且b大于15,返回false"
fi
#测试或运算
if [ $a -lt 100 -o $b -gt 100 ]
then 
	echo "a小于100或者b大于100:返回true"
else
	echo "a小于100或者b大于100:返回false"
fi
#测试非运算
if [ ! $a -lt 100 ]
then
	echo "a小于100的非运算:返回true"
else
	echo "a小于100的非运算:返回false"
fi

结果为

a小于100并且b大于15,返回true
a小于100或者b大于100:返回true
a小于100的非运算:返回false

3.6.4 逻辑运算符

下表列出常用的逻辑运算符,假定变量a为10,变量b为20

运算符说明举例
&&逻辑的AND[[ $a -lt 100 && $b -gt 100 ]] 返回false
||逻辑的OR[[ $a -lt 100 || $b -gt 100 ]]返回true

示例

#!/bin/sh
a=10
b=20
#测试逻辑与
if [[ $a -lt 100 && $b -gt 100 ]]
then 
	echo "a小于100并且b大于100:返回true"
else
	echo "a小于100并且b大于100:返回false"
fi
#测试逻辑或
if [[ $a -lt 100 || $b -gt 100]]
then 
	echo "a小于100或者b大于100:返回true"
else
	echo  "a小于100或者b大于100:返回false"
fi

结果为

a小于100并且b大于100:返回false
a小于100或者b大于100:返回true

3.6.5 字符串运算符

下表列出了常用的字符串运算符,假定变量a为"abc",变量b为"efg"

运算符说明举例
=检测连个字符串是否相等,相等返回true[ $a = $b ] 返回false
!=检测两个字符串是否不相等,不相等返回true[ $a != #b ] 返回true
-z检测字符串长度是否为0,为0返回true[ -z $a ] 返回false
-n检测字符串长度是否为0,不为0返回true[ -n “$a” ] 返回true
$检测字符串是否为空,不为空返回true[ $a ] 返回true

示例

#!/bin/sh
a=abc
b=efg
#测试两个字符串是否相等
if [ $a = $b ]
then 
	echo "字符串a等于字符串b"
else 
	echo "字符串a不等于字符串b"
fi
#测试两个字符串是否不相等
if [ $a != $b ]
then 
	echo "字符串a不等于字符串b"
else
	echo "字符串a等于字符串b"
fi
#测试字符串长度是否为0
if [ -z $a ]
then 
	echo "字符串a的长度为0"
else
	echo "字符串a的长度不为0"
fi
#测试字符串长度是否为0,第二种方法
if [ -n $a ]
then 
	echo "字符串a的长度不为0"
else
	echo "字符串b的长度为0"
fi
#判断字符串是否为空
if [ $a ]
then 
	echo "字符串不为空"
else
	echo "字符串为空"
fi

结果为:

字符串a不等于字符串b
字符串a不等于字符串b
字符串a的长度不为0
字符串a的长度不为0
字符串不为空

3.6.6 文件测试运算符

下表列出了常用的文件测试运算符

运算符说明
-b file检测文件是否是块设备文件,如果是,则返回true
-c file检测文件是否是字符设备文件,如果是,则返回true
-d file
-f file
-g file
-k file
-p file
-u file
-r file

版权声明:本文为qq_38502736原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。