shell脚本1-基础使用

1. shell脚本的基本结构与执行

1.1 基本结构

shell脚本的后缀名一般为sh,并且在最开始需要指明执行脚本的解释器(即具体使用哪一种shell)

#!/bin/bash

1.2 执行

如果想要让脚本作为可执行文件来执行,则需要为其增加执行权限,即使用chmod来操作

chmod +x ./test.sh
# 添加执行权限后,此时可以直接使用./来执行脚本
./test.sh

1.3 注释

注释分为单行注释和多行注释,其中单行注释使用 # 即可,多行注释则有特定的写法

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

其中的 EOF 可以使用其他的符号,比如:

:<<'
注释内容...
注释内容...
注释内容...
'

:<<!
注释内容...
注释内容...
注释内容...
!

2. 变量

2.1 变量的定义与赋值

定义变量时,变量名不加 $ 符号,另外,需要注意的是,变量名和等号之间不能加空格,例如

varible="123456"

此外,变量的命名规则为:

  • 变量命名只能用英文字母、数字、下划线,且首字符不能为数字
  • 变量名中间不能有空格、标点符号
  • 不能使用保留字

除了可以显式直接对变量赋值外,还可以使用语句为变量赋值,如:

for file in 'ls /etc'
for file in $(ls /etc)

有一种变量类型为只读变量,该变量仅可读,不允许被修改

var_1="1234"
readonly var_1
var_1="5" # 报错

2.2 使用变量

要使用一个已经定义过的变量,则需要在变量名前面添加 $ 符号,此外,$ 后面的大括号是可以省略的,但是一般情况下,加上这个大括号可以更好地区分变量的边界,最好是加上。

var_1="12345"
echo $var_1
echo ${var_1}

已定义的变量,可以被重新定义

var_2="before"
echo ${var_2} # 输出为before
var_2="after"
echo ${var_2} # 输出为after

当变量不再需要时,可以删除变量,但是不能删除只读变量。同时需要注意的是,这里的unset后面直接跟变量名,不需要加 $ 符号

unset var_2

2.3 变量类型(作用范围)

  • 局部变量:局部变量在脚本或命令中定义,仅在当前的shell中有效,其他的shell启动的程序不能访问
  • 环境变量:所有的程序,包括shell启动的程序,都可以访问环境变量,有些程序需要环境变量来保证其正常运行,shell脚本也可以定义环境变量
  • shell变量:由shell程序设置的特殊变量,shell变量中有一部分是环境变量,有一部分是局部变量,保证了shell的正常运行

3. 数据类型

数据类型本应属于变量的范畴,但是因为太多了,就单独拿出来

3.1 字符串

shell中的字符串可以用单引号,也可以用双引号,也可以不用引号,但是三种用法之间略有不同

str_1='string1'
str_2="string2"
str_3=string3

这些不同的字符串也会在进行拼接的时候略有不同

3.1.1 单引号字符串限制

  • 单引号内的任何字符都会原样输出,其中的变量无效
  • 单引号字符串不能只出现一个单独的引号,需要成对出现,(对单引号使用转义符后需要成对出现)。
str_1=' \'string1''
str_2='string2 and ${str_1}'
echo ${str_2} 
# 此时的输出为 string2 and ${str_1}
  • 由于单引号字符串里面不能有转义字符出现,因此,需要分三段进行拼接
your_name="name1"
# 使用单引号拼接
greeting_2='hello, '$your_name' !'
greeting_3='hello, ${your_name} !'
echo $greeting_2  $greeting_3
# 此时的输出为 hello, name1 ! hello, ${your_name} !

3.1.2 双引号字符串限制

  • 双引号里可以有变量
  • 双引号里可以出现转义字符
your_name="name2"
# 比如下面这个转义字符
str="Hello, I know you are \"$your_name\"! \n"
echo -e $str
# 输出结果为 Hello, I know you are "name2"! 
  • 由于此时的双引号内可以添加转义字符,因此这里的字符串拼接会相对来说更加灵活一些
your_name="name2"
# 使用双引号拼接
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting  $greeting_1
# 输出结果为 hello, name2 ! hello, name2 !

3.1.3 获取字符串长度

使用#可以获得

string="abcd"
echo ${#string} # 输出为4

3.1.4 提取子字符串

提取子字符串时,第一个字符的索引为0,因此下面这个例子是表示从第2个字符开始截取4个字符

string="1234567890"
echo ${string:1:4}

3.1.5 查找子字符串

查找字符第一次出现的位置,下面这个例子是查找字符i或者o的位置(哪个先出现就算哪个)

string="1i2o3i4p567"
echo `expr index "${string}" io` # 输出为2

3.2 数组

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

类似于C语言,数组元素的下标从0开始编号,获取数组中的元素可以通过下标来获取,其中下标可以是数字或者表达式,值应>=0

3.2.1 定义

数组的定义,用括号表示数组,元素使用空格隔开,一般形式为:

数组名=(值1 值2 值3 ... 值n)
# 例如下面这个例子
array_name=(value0 value1 value2 value3)
# 也可以写为
array_name=(
value0
value1
value2
value3
)
# 也可以单独定义各个值,数组可以使用不连续的下标,并且下标的范围没有限制
array_name[0]=value0
array_name[1]=value1
array_name[n]=valuen

3.2.2 读取

一般的格式为:

${数组名[下标]}
# 例如
valuen=${array_name[n]}

如果需要获取数组中的所有元素,则需要使用 @ ,即:

echo ${array_name[@]}

3.2.3 获取数组长度

获取数组长度的方式与获取字符串长度方式相同,也是用#

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

4. 传递参数

在执行脚本时,可以通过命令行向脚本传递参数,脚本内获取参数的格式为 $n,其中的n表示第n个参数。例如下面一个脚本

#!/bin/bash

echo "脚本文件名为:$0"
echo "第一个参数为:$1"
echo "第一个参数为:$2"
echo "第一个参数为:$3"

此时执行脚本可以得到结果为:

./test.sh 1 2 3
脚本文件名为:./test.sh
第一个参数为:1
第二个参数为:2
第三个参数为:3

此外,还有一些特殊的参数

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

$*$@ 区别:

  • 相同点:都是引用所有参数。
  • 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 " * " 等价于 “1 2 3”(传递了一个参数),而 “@” 等价于 “1” “2” “3”(传递了三个参数)。
#!/bin/bashecho "-- \$* 演示 ---"for i in "$*"; do    echo $idoneecho "-- \$@ 演示 ---"for i in "$@"; do    echo $idone

执行的结果为:

$ ./test.sh 1 2 3
-- $* 演示 ---
1 2 3
-- $@ 演示 ---
1
2
3

5. 运算符

shell支持多种运算符,包括算数运算符、关系运算符、布尔运算符、字符串运算符、文件测试运算符

5.1 算术运算符

由于原生的bash不支持简单的数学运算,因此需要通过一些命令来实现,比如awk、expr等,其中expr最常用

expr是一个用于表达式计算的工具,可以完成表达式的求值操作。

需要注意的是:

  • 表达式和运算符之间要有空格,比如必须写成 2 + 2,而不能写成 2+2
  • 完整的表达式要被 ` ` 包含。

例如下面一个求两数之和的操作

val=`expr 2+2`
echo "两数之和为:${val}" # 输出结果为4

下面是常用的算术运算符,需要注意的是,对于相等、不相等的条件表达式,需要放在方括号之间,并且需要有空格,例如:

[ $a == $b ] 是正确的,而 [$a==$b] 是错误的

运算符说明举例
+加法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。

具体的例子如下:

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"

if [ $a == $b ]
then
   echo "a 等于 b"
fi
if [ $a != $b ]
then
   echo "a 不等于 b"
fi

5.2 关系运算符

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

运算符说明举例
-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。

下面的例子假定a=10,b=20

a=10
b=20

if [ $a -eq $b ]
then
   echo "$a -eq $b : a 等于 b"
else
   echo "$a -eq $b: a 不等于 b"
fi
if [ $a -ne $b ]
then
   echo "$a -ne $b: a 不等于 b"
else
   echo "$a -ne $b : a 等于 b"
fi
if [ $a -gt $b ]
then
   echo "$a -gt $b: a 大于 b"
else
   echo "$a -gt $b: a 不大于 b"
fi
if [ $a -lt $b ]
then
   echo "$a -lt $b: a 小于 b"
else
   echo "$a -lt $b: a 不小于 b"
fi
if [ $a -ge $b ]
then
   echo "$a -ge $b: a 大于或等于 b"
else
   echo "$a -ge $b: a 小于 b"
fi
if [ $a -le $b ]
then
   echo "$a -le $b: a 小于或等于 b"
else
   echo "$a -le $b: a 大于 b"
fi

5.3 布尔运算符

运算符说明举例
!非运算,表达式为 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。

例子:

a=10
b=20

if [ $a != $b ]
then
   echo "$a != $b : a 不等于 b"
else
   echo "$a == $b: a 等于 b"
fi
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 5 -o $b -gt 100 ]
then
   echo "$a 小于 5 或 $b 大于 100 : 返回 true"
else
   echo "$a 小于 5 或 $b 大于 100 : 返回 false"
fi

输出结果为:

10 != 20 : a 不等于 b
10 小于 100 且 20 大于 15 : 返回 true
10 小于 100 或 20 大于 100 : 返回 true
10 小于 5 或 20 大于 100 : 返回 false

5.4 逻辑运算符

假定变量 a 为 10,变量 b 为 20:

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

例子:

a=10
b=20

if [[ $a -lt 100 && $b -gt 100 ]]
then
   echo "返回 true"
else
   echo "返回 false"
fi

if [[ $a -lt 100 || $b -gt 100 ]]
then
   echo "返回 true"
else
   echo "返回 false"
fi

输出结果为:

返回 false
返回 true

5.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。

例子:

a="abc"
b="efg"

if [ $a = $b ]
then
   echo "$a = $b : a 等于 b"
else
   echo "$a = $b: a 不等于 b"
fi
if [ $a != $b ]
then
   echo "$a != $b : a 不等于 b"
else
   echo "$a != $b: a 等于 b"
fi
if [ -z $a ]
then
   echo "-z $a : 字符串长度为 0"
else
   echo "-z $a : 字符串长度不为 0"
fi
if [ -n "$a" ]
then
   echo "-n $a : 字符串长度不为 0"
else
   echo "-n $a : 字符串长度为 0"
fi
if [ $a ]
then
   echo "$a : 字符串不为空"
else
   echo "$a : 字符串为空"
fi

输出结果

abc = efg: a 不等于 b
abc != efg : a 不等于 b
-z abc : 字符串长度不为 0
-n abc : 字符串长度不为 0
abc : 字符串不为空

6. 流程控制

6.1 if-else

if-else语句分为三种,一种是单if,一种是单if+else,一种是if+elif+else

  • if语句

    if语法格式

    if condition
    then
    	command1
    	command2
    	...
    	commandn
    fi
    

    如果写成1行,则有:

    if [ $(ps -ef | grep -c "ssh") -gt 1 ]; then echo "true"; fi
    
  • if-else语句

    if condition
    then
    	command1
    	command2
    	...
    	commandn
    else
    	command
    fi
    
  • if-elif-else语句

    if condition1
    then
    	command1
    elif condition2
    then
    	command2
    else
    	command3
    fi
    

下面是一个例子,判断a和b的大小关系

a=10
b=20
if [ ${a} -eq ${b} ]
then
	echo "a = b"
elif [ ${a} -gt ${b} ]
then
	echo "a > b"
elif [ ${a} -lt ${b} ]
then
	echo "a < b"
else
	echo "error"
fi
# 输出为 a < b

if-else语句经常与test命令结合使用,如下所示

num1=$[2*3]
num2=$[1+5]
if test $[num1] -eq $[num2]
then
    echo '两个数字相等!'
else
    echo '两个数字不相等!'
fi

6.2 for循环

for循环的一般格式为:

for var in item1 item2 ... itemN
do
	command1
	command2
	...
	commandN
done

如果写成一行,则为

for var in item1 item2 ... itemN; do command1; command2… done;

当变量的值在列表中,for循环就会执行一次所有命令,使用变量名获取列表中的当前取值。命令可以为任何有效的shell命令和语句。in列表可以包含替换、字符串、文件名

6.3 while语句

while语句的基本格式为:

while condition
do
	command1
	command2
	...
	commandN
done

例子:

int=1
while(( $int<=5 ))
do
    echo $int
    let "int++"
done

6.4 until循环

until 循环执行一系列命令直至条件为 true 时停止。

until 循环与 while 循环在处理方式上刚好相反。

一般 while 循环优于 until 循环,但在某些时候—也只是极少数情况下,until 循环更加有用。

until condition
do
    command
done

例子:

a=0

until [ ! $a -lt 10 ]
do
   echo $a
   a=`expr $a + 1`
done

6.5 case语句

shell中的case语句需要注意,break使用 ;; 来表示。

case 值 in
模式1)
    command1
    command2
    ...
    commandN
    ;;
模式2)
    command1
    command2
    ...
    commandN
    ;;
esac

下面是一个例子

echo '输入 1 到 4 之间的数字:'
echo '你输入的数字为:'
read aNum
case $aNum in
    1)  echo '你选择了 1'
    ;;
    2)  echo '你选择了 2'
    ;;
    3)  echo '你选择了 3'
    ;;
    4)  echo '你选择了 4'
    ;;
    *)  echo '你没有输入 1 到 4 之间的数字'
    ;;
esac

6.6 跳出循环

  • break命令

    例子:

    while :
    do
        echo -n "输入 1 到 5 之间的数字:"
        read aNum
        case $aNum in
            1|2|3|4|5) echo "你输入的数字为 $aNum!"
            ;;
            *) echo "你输入的数字不是 1 到 5 之间的! 游戏结束"
                break
            ;;
        esac
    done
    
  • continue命令

    while :
    do
        echo -n "输入 1 到 5 之间的数字: "
        read aNum
        case $aNum in
            1|2|3|4|5) echo "你输入的数字为 $aNum!"
            ;;
            *) echo "你输入的数字不是 1 到 5 之间的!"
                continue
                echo "游戏结束"
            ;;
        esac
    done
    

7. 函数

函数的基本定义如下,需要注意的是,下面的 [] 表示可选项,并不是需要带在代码里面的,也就是说:

  • 可以通过 function func_name() 来定义,也可以直接用 func_name(),或者 func_name 来定义
  • 对于参数返回,可以显式加 return 内容,如果不加,则表示无返回值,这里返回的内容为数值(0-255)
  • 函数的返回值在调用了该函数之后通过 $? 获取,这里需要注意的是,如果在函数后,没有立即查看 $? 的值,而是先插入了一条别的 echo 命令,最后再查看 $? 的值得到的是 0,也就是上一条 echo 命令的结果,而先前调用的函数的返回值被覆盖了
  • 函数的参数,只需在函数内部通过 $n 的方式来获取,这个获取方式与取命令行参数是类似的
[ function ] func_name [()]
{
	command;
	[return int;]
}

具体的例子

funWithReturn(){
    echo "这个函数会对传入的两个数字进行相加运算..."
    aNum=$1
    anotherNum=$2
    echo "参数一共有 $# 个"
    echo "两个数字分别为 $aNum 和 $anotherNum !"
    return $(($aNum+$anotherNum))
}
funWithReturn(1,2)
echo "输入的两个数字之和为 $? !"

8. 外部包含

shell也可以包含外部脚本,这样可以很方便地封装一些公用的代码作为一个独立的文件

. filename # 注意中间有个空格
source filename

注意,被包含的文件不需要可执行的权限,只需要写内容即可

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值