Shell脚本基础教程

在这里插入图片描述

Shell脚本基础教程

Shell参数定义

定义变量

想要定义变量,只需要使用如下命令即可。

variable_name=variable_value

variable_name表示变量名,variable_value表示变量值。注意,等号与变量名和变量值之间不能有空格

变量名的命名需要遵循如下规则:

  1. 变量名的组成只能是英文字母、数字和下划线
  2. 首字母只能是英文字母和下划线,不能是数字

正确示例:

test="test"
_test=123

错误示例:

1test="test"
test%test=123
test = "test"

使用变量

定义了变量,就要使用变量。使用变量的时候,需要在变量名称前加上符号$

# 定义变量
test="hello world"

# echo是用于字符串输出的命令,这里将变量test输出到控制台
echo $test
echo ${test}!
# 输出结果
hello world
hello world!

由上面的示例,我们看到了变量名外面的花括号是可选的,加花括号是为了帮助识别变量的边界。

推荐给所有变量加上花括号,这是个好的编程习惯。

修改变量

定义的变量是可以修改的,再设置变量的值即可。

# 设置变量test的值为hello world,并打印
test="hello world"
echo ${test}

# 修改变量test的值为hello shell,并打印
test="hello shell"
echo ${test}
# 输出结果
hello world
hello shell

只读变量

使用readonly命令可以将变量定义为只读变量,只读变量的值不能被改变。

# 定义一个变量test
test="222"

# 设置test变量为只读
readonly test

# 修改test变量值为111,修改失败
test="111"
# 输出
test: readonly variable

提示信息告诉,test变量是一个只读的变量,不允许修改。

删除变量

使用unset命令可以删除变量。

# 定一个一个变量test,并打印
test="222"
echo "test的值为:$test"

# 删除变量test,再打印,发现没有了
unset test
echo "test的值为:$test"
# 输出
test的值为:222
test的值为:

刚才我们说使用readonly命令可以将变量定义为只读变量,那只读变量是否允许删除呢?

# 定一个一个变量test,并打印
test="222"
echo "test的值为:$test"

# 设置变量test为只读
readonly test

# 删除变量test,再打印,发现还有,说明没有删除成功
unset test
echo "test的值为:$test"
# 输出
test的值为:222
./test.sh: line 6: unset: test: cannot unset: readonly variable
test的值为:222

根据输出,我们发现了,只读变量是不允许删除的

变量的作用域

变量的作用域也就是变量可以使用的范围。根据变量的作用域,可以将变量分为三种。

  • 局部变量
  • 全局变量
  • 环境变量
局部变量

有的变量只能在函数内部使用,这叫做局部变量。

为了演示局部变量,使用了Shell函数的概念,若不清楚,可点击跳转先学习下函数

# 定义了一个名为hello的函数
function hello()
{
        local name="Shell"
        echo "函数内获取:$name"
}

# 调用hello函数
hello

echo "函数外获取变量:$name"
# 输出
$ sh variables-scope.sh
函数内获取:Shell
函数外获取变量:

通过输出我们可以看到,使用了local定义的变量成为了局部变量,在函数内可以获取到此变量,但是在函数外获取不到这个变量。

全局变量

全局变量是指在当前的整个Shell进程中都有效的变量。每个Shell进程都有自己的作用域,彼此之间互不影响。在Shell脚本中定义的变量,默认就是全局变量。

#!/bin/bash

# 在脚本中定义了一个变量name,这个变量默认就是全局变量,在整个shell脚本中都可以访问
name="shell"

# 函数内获取变量
function printName()
{
        echo "函数内获取名字为:$name"
}

# 函数外获取变量
echo "函数外获取姓名为:$name"
printName
# 输出
$ sh variables.sh
函数外获取姓名为:shell
函数内获取名字为:shell

由此可以知道,当我们直接定义一个变量的时候,默认是全局变量,整个shell脚本中都可以访问。

环境变量

全局变量只在当前 Shell 进程中有效,对其它 Shell 进程和子进程都无效。我们可以使用export命令,将变量转变为环境变量,这样Shell子进程中就可以访问到Shell父进程的变量了。当然两个没有父子关系的 Shell 进程是不能传递环境变量的。

# 以下操作在命令行中直接进行,才可以看到输出结果
name="shell"
echo "父进行中访问姓名为:$name"

bash
echo "子进程中访问姓名为:$name"

exit

export name
bash
echo "子进程中访问姓名为:$name"

age=20
echo "子进程中访问年龄为:$age"
export age
exit

echo "父进程中访问年龄为:$age"
# 输出
父进行中访问姓名为:shell
子进程中访问姓名为:
子进程中访问姓名为:shell
子进程中访问年龄为:20
父进程中访问年龄为:

由输出结果可以看出,使用export命令之后,子进程中已经可以获取到name变量了。但是子进程export的变量,父进程也是访问不到的。

变量的类型

字符串

字符串是shell编程中最常用最有用的数据类型。字符串可以用单引号,也可以用双引号,也可以不用引号。

  • 单引号:任何字符都会原样输出,单引号字符串中的变量是无效的
  • 双引号:双引号里可以有变量,双引号里可以出现转义字符

字符串还有一些常用的操作,请继续学习。

获取字符串长度
# 定义一个字符串变量,并输出字符串的长度
str="Hello World!"
echo 字符串的长度为:${#str}
# 输出
字符串的长度为:12

我们知道${variable_name}便是使用一个变量,由上面的例子,我们知道了,在变量名之前,加上#符号即${#variable_name},便可获取字符串变量的长度。

获取子字符串
str="Hello World!"
echo 位置1之后的5位字符串为:${str:0:5}
# 输出
位置1之后的5位字符串为:Hello

${variable_name:index:length}在变量名后加上子字符串开始的位置以及长度,即可获取子字符串。这里需要注意的是,索引位置是以0开始,所以index为0表示第一个字符。

查找子字符串位置
str="Hello World!"
echo o字符在字符${str}上的位置为:`expr index "${str}" o`
# 输出
o字符在字符Hello World!上的位置为:5

括住expr index "${str}" o的是反引号,表示要执行里面的内容,这里需要注意。

这里使用了expr命令来取得子字符串的位置。expr index $string $substring表示要在字符串string中找到字符串substring的位置。

更多expr命令的用法读者可以继续深入了解。

数组
定义数组

想要定义数组,可以用括号来表示数组,数组元素用"空格"符号分割。

array_name=(value0 value1 value2 value3)

或者

array_name=(
value0
value1
value2
value3
)
读取数组内元素

想要读取数组,可以使用如下命令:

# 获取数组array_name的索引index的元素
${array_name[index]}

# 获取数组array_name的索引index的元素,并赋值给value
value=${array_name[index]}

# 获取数组中的所有元素
${array_name[@]}

使用示例如下:

arr=("张三" "李四" "王五")

value=${arr[0]}
echo $value
# 输出
张三
获取数组长度

获取数组长度的方法与获取字符串长度的方法类似。

${#array_name[@]}

Shell注释

单行注释

#开头的行就是注释。就像下面这样:

#--------------------------------------------
# 这是一行注释
#--------------------------------------------

多行注释

:<<EOF开头,EOF结尾的便是多行注释。其中EOF可以替换成其他的字符,下面是两个多行注释的例子

:<<EOF
第一行注释
第二行注释
第三行注释
EOF

:<<HAHA
第一行注释
第二行注释
第三行注释
HAHA

Shell流程控制

分支语句

if else语句

if语句的语法如下:

if condition
then
    command1 
    command2
    ...
    commandN 
fi

也可以写成一行,关键点在于使用分号;作为语句的分割

if condition; then command; fi

意思是:如果condition语句成立,则执行then之后的语句,直到出现fi

使用示例演示下if语句的使用。

# 使用test命令判断脚本输入第一个参数和第二个参数的字符是否相等
if test $1 = $2
then
        echo "相等"
fi

if test $1 != $2
then
        echo "不相等"
fi
$ sh test.sh aaa aaa
相等

$ sh test.sh aaa zzz
不相等
# 将if语句写成一行
$ if test 1 -eq 1;then echo "相等";fi
相等

if else 语法`格式:

if condition
then
    command1 
    command2
    ...
    commandN
else
    command
fi

意思是:如果condition语句成立,则执行then之后的语句。若是不成立,则执行else之后的语句,直到出现fi

使用示例演示如下所示:

# 使用test命令判断脚本输入第一个参数指定的文件是否存在
if test -e $1
then
        echo "文件存在"
else
        echo "文件不存在"
fi
# 输出
$ sh test.sh "test.sh"
文件存在

$ sh test.sh "test.sh1"
文件不存在

if else-if else 语法格式:

if condition1
then
    command1
elif condition2 
then 
    command2
else
    commandN
fi

意思是:如果condition1语句成立,则执行then之后的语句。若是不成立,则继续判断condition2是否成立,若成立,则执行then之后的语句。若还是不成立,则执行else之后的语句,直到出现fi

使用示例演示如下所示:

# 使用test命令判断脚本输入第一个参数和第二个参数的大小比较
if test $1 -eq $2
then
        echo "数值相等"
elif test $1 -gt $2
then
        echo "$1大于$2"
else
        echo "${1}小于${2}"
fi
# 输出
$ sh test.sh 10 10
数值相等

$ sh test.sh 10 11
10小于11

$ sh test.sh 12 11
12大于11
case语句

case语句为多选择语句。可以用case语句匹配一个值与一个模式,如果匹配成功,执行相匹配的命令。

case语句格式如下:

casein
模式1)
    command1
    command2
    ...
    commandN
    ;;
模式2)
    command1
    command2
    ...
    commandN
    ;;
esac

模式取值可以为变量或常数,每一模式必须以右括号结束。匹配发现取值符合某一模式后,其间所有命令开始执行直至 ;;

取值将检测匹配的每一个模式。

一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。

循环语句

for循环

for循环语句格式为:

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

也可以写成一行

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

示例如下:

for value in 1 2 3 4 5
do
    echo "The value is: $value"
done
# 输出
The value is: 1
The value is: 2
The value is: 3
The value is: 4
The value is: 5
while循环

while循环的语句格式如下:

while condition
do
    command
done

condition语句判断为true时,执行command语句;执行结束之后,继续判断condition语句,直到为false,结束执行。

示例如下:

value=1
while(( $value<=5 ))
do
    echo 值为:$value
    let "value++"
done
# 输出
值为:1
值为:2
值为:3
值为:4
值为:5
跳出循环

在循环的过程中,经常需要做出跳出循环的操作。这里又包含了两种情况,一种是跳出当前循环,进入下一次循环;另一种是,直接跳出循环语句,执行循环语句后面的代码。

第一种,跳出当前循环,进入下一次循环,使用continue命令。

第二种,跳出循环,使用break命令。

Shell函数

定义函数

可以在Shell脚本内定义函数。格式如下所示:

[ function ] functioName [()]

{

    action;

    [return int;]

}
  1. function关键字是可选的,可以设置,也可以不设置。

若对这个格式不是很理解,我们接下来就详细来说明。

我们先来尝试简单地使用函数。我们先定义一个函数,然后再调用它。如下所示:

# 定义一个函数,名为getName,其作用为打印字符串Shell
function getName(){
  echo "Shell"
}

# 调用函数getName
getName
# 输出
Shell

调用函数

直接使用函数名称即可调用函数。

在函数名称后面,再带上一些参数,便是调用函数并给函数传递了一些参数。

# 定义一个函数getName
function getName(){
  echo "Shell"
}

# 直接使用函数名调用函数
getName

# 定义一个函数hello
function hello(){
  echo "Hello $1"
}

# 直接使用函数名调用函数,并传递了一个字符串作为参数
hello "孙悟空"
# 输出
Shell
Hello 孙悟空

函数参数

函数是支持传递参数的,在函数体内部,通过$n的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数,以此类推。注意,$10不能获取第十个参数,获取第十个参数需要${10}。当n>=10时,需要使用${n}来获取参数。

# 定义一个函数hello
function hello(){
  echo "Hello $1"
}

# 直接使用函数名调用函数,并传递了一个字符串作为参数
hello "孙悟空"
# 输出
Hello 孙悟空

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

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

函数返回值

函数的返回值,可以显式使用关键字return返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值,可选值为0-255

return表示退出函数并返回一个退出值,脚本中可以在调用函数后,用$?获取到该退出值。

# 定义了一个函数sum,read命令用于在执行中输入数字,并设置到参数firstNum和secondNum
function sum(){
    echo "这个函数会对输入的两个数字进行相加运算..."
    echo "输入第一个数字: "
    read firstNum
    echo "输入第二个数字: "
    read secondNum
    echo "两个数字分别为 $firstNum$secondNum"
    return $(($firstNum+$secondNum))
}

# 运行函数sum,并通过$?获取到函数的返回值进行打印
sum
echo "输入的两个数字之和为$?"
# 输出
这个函数会对输入的两个数字进行相加运算...
输入第一个数字:
1
输入第二个数字:
2
两个数字分别为 12
输入的两个数字之和为3

函数返回值在调用该函数后通过$?来获得。

递归调用函数

什么叫做递归调用,便是函数自己调用自己。

函数库

一些注意事项

  1. 所有函数在使用前必须定义。这意味着必须将函数放在脚本开始部分,直至shell解释器首次发现它时,才可以使用。
  2. Shell函数中定义的变量默认也是全局变量,它和在函数外部定义变量拥有一样的效果。

常见的命令

echo

echo命令用于字符串的输出。命令格式:

echo string

printf

printf也是一个输出命令,但是可以格式化字符串。命令格式:

printf  format-string  [arguments...]

test命令

Shell中的test命令用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试。

数值测试
参数说明
-eq等于则为真
-ne不等于则为真
-gt大于则为真
-ge大于等于则为真
-lt小于则为真
-le小于等于则为真
# 使用test命令判断脚本输入第一个参数和第二个参数的大小比较
if test $1 -eq $2
then
        echo "数值相等"
elif test $1 -gt $2
then
        echo "$1大于$2"
else
        echo "${1}小于${2}"
fi
# 输出
$ sh test.sh 10 10
数值相等

$ sh test.sh 10 11
10小于11

$ sh test.sh 12 11
12大于11
字符串测试
参数说明
=等于则为真
!=不相等则为真
-z 字符串字符串的长度为零则为真
-n 字符串字符串的长度不为零则为真
# 使用test命令判断脚本输入第一个参数和第二个参数的字符是否相等
if test $1 = $2
then
        echo "相等"
fi

if test $1 != $2
then
        echo "不相等"
fi
$ sh test.sh aaa aaa
相等

$ sh test.sh aaa zzz
不相等
文件测试
参数说明
-e 文件名如果文件存在则为真
-r 文件名如果文件存在且可读则为真
-w 文件名如果文件存在且可写则为真
-x 文件名如果文件存在且可执行则为真
-s 文件名如果文件存在且至少有一个字符则为真
-d 文件名如果文件存在且为目录则为真
-f 文件名如果文件存在且为普通文件则为真
-c 文件名如果文件存在且为字符型特殊文件则为真
-b 文件名如果文件存在且为块特殊文件则为真
# 使用test命令判断脚本输入第一个参数指定的文件是否存在
if test -e $1
then
        echo "文件存在"
else
        echo "文件不存在"
fi
# 输出
$ sh test.sh "test.sh"
文件存在

$ sh test.sh "test.sh1"
文件不存在

其他

Shell中$各种含义

符 号含 义
$0脚本名
$#参数个数
$n传递给脚本的参数值,$1表示第1参数、$2表示第2参数
$?上次退出的状态(返回值),0没有错误,1错误
$*所有参数列表。"$*“时,是”$1 $2 … $n"的形式
$@所有参数列表。“$@“时,是”$1” “ 2 " … " 2" … " 2""n” 的形式
$$当前进程的编号(ProcessID)
$!shell最后运行的后台Process的PID
$var变量,会与后面的连接,如$var_a,会当做变量var_a
${var}变量,界定范围
$()(反引号)类似,里面执行完再返回值,所有shell通用
$[]可进行算术运算和逻辑运算,不支持浮点和字符串
$(())可进行算术运算和逻辑运算,不支持浮点和字符串。里面的变量可以省略$
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值