项目实训(树莓派)(十五)树莓派4B下的ubuntu系统下的Bash的使用和脚本初步-第一部分(变量 脚本 字符串等)

目录

Bash介绍

实验目的

实验环境

实验步骤与内容:

1.编写并执行第一个Bash脚本

2.Bash变量

3.Bash字符串

4.Bash数组

5.Bash注释

6.Bash传递参数


Bash介绍

Bash是一个命令处理器,通常运行于文本窗口中,并能执行用户直接输入的命令。Bash还能从文件中读取命令,这样的文件称为脚本。和其他Unix shell 一样,它支持文件名替换(通配符匹配)、管道here文档、命令替换、变量,以及条件判断和循环遍历的结构控制语句。

Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。

Bash,也就是 Bourne Again Shell,由于易用和免费,Bash 在日常工作中被广泛使用。同时,Bash 也是大多数Linux 系统默认的 Shell。

在一般情况下,人们并不区分 Bourne Shell 和 Bourne Again Shell,所以,像 #!/bin/sh,它同样也可以改为 #!/bin/bash

实验目的

掌握Bash命令处理器的使用

实验环境

树莓派4B、系统:Ubuntu 20.10系统 、vim软件

实验步骤与内容:

1.编写并执行第一个Bash脚本

打开终端,通过vim命令来创建文件,新建一个文件test.sh,扩展名为sh(sh代表shell),扩展名并不会影响脚本的执行,如果使用python来写shell脚本,扩展名使用py就好了。

在vim编辑器中输入下面的代码:

#!/bin/bash
#This is a example
echo "Hello World !"

这样我们第一个Bash程序就写完了。接下来解释一下这个简单的程序:

(1)第一行的 #! 和/bin/bash是什么意思

#! 是说明 test 这个文件的类型的,有点像 Windows 系统下用不同文件后缀来表示不同文件类型的意思(但不是完全相同)。Linux 系统根据 "#!" 及该字串后面的信息确定该文件的类型,关于这一问题同学们回去以后可以通过 "man magic"命令 及 /usr/share/magic 文件来了解这方面的更多内容。

在 BASH 中 第一行的 "#!" 及后面的 "/bin/bash" 就表明该文件是一个 BASH 程序,需要由 /bin 目录下的 bash 程序来解释执行。BASH 这个程序一般是存放在 /bin 目录下,如果你的 Linux 系统比较特别,bash 也有可能被存放在 /sbin 、/usr/local/bin 、/usr/bin 、/usr/sbin 或 /usr/local/sbin 这样的目录下;如果还找不到,你可以用 "locate bash" "find / -name bash 2> /dev/null" 或 "whereis bash" 这三个命令找出 bash 所在的位置;如果仍然找不到,那你可能需要自己动手安装一个BASH 软件包了。
(2)第二行是注释吗 

第二行的 "# This is a example" 就是 BASH 程序的注释,在 BASH 程序中从“#”号(注意:后面紧接着是“!”号的除外)开始到行尾的多有部分均被看作是程序的注释。
(3)echo 语句

第三行的echo语句的功能就是把echo 后面的字符串输出到标准输出中去。由于 echo 后跟的是 "Hello World" 这个字符串,因此 "Hello World"这个字串就被显示在控制台终端的屏幕上了。需要注意的是 BASH 中的绝大多数语句结尾处都没有分号。

接下来就是运行这个Bash脚本,一共有两种办法:

1.作为可执行程序

将上面的文件保存为test.sh,并通过命令行移动到相应的目录之下,之后输入以下命令:

$ chmod +x ./test.sh  #使得该脚本具有执行的权限
$ ./test.sh #执行脚本

注意,这里一定要写成 ./test.sh,而不是 test.sh,运行其它二进制的程序也一样,直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 test.sh 是会找不到命令的,要用 ./test.sh 告诉系统说,就在当前目录找。

执行结果如下:

2.作为解释器参数

这种运行方式是,直接运行解释器,其参数就是 shell 脚本的文件名,如:

$ /bin/sh test.sh 或者
$ bash test.sh

执行结果如下:

这是由于 hello 文件第一行的 "#! /bin/bash" 的作用,系统会自动用/bin/bash 程序去解释执行 hello 文件的。

需要注意的是,BASH 程序被执行后,实际上 Linux 系统是另外开设了一个进程来运行的。

2.Bash变量

接下来我们就先看看Bash中的变量是如何定义和使用的。

定义变量时,变量名不加美元符号($,PHP语言中变量需要),如:

my_name="shumeipai"

注意,变量名和等号之间不能有空格,这可能和你熟悉的所有编程语言都不一样。同时,变量名的命名须遵循如下规则:

  • 命名只能使用英文字母,数字和下划线,首个字符不能以数字开头。
  • 中间不能有空格,可以使用下划线(_)。
  • 不能使用标点符号。
  • 不能使用bash里的关键字(可用help命令查看保留关键字)。

以下举例一些有效的Shell变量名:

zhonghua
_shumeipai
sdu6
SDU

无效的变量命名:

v ar=123
use?name=hh

除了显式的直接进行赋值,还可以用语句来给变量赋值,例如:

for file in 'ls Documents'
或
for file in $(ls Documents)

上述语句可以将Documents目录下的文件名循环打印下来。

使用变量

使用一个定义过的变量,只需要在变量名之前加上美元符号即可,例如:

zhonghua="China"
echo $zhonghua
或
echo ${zhonghua}

变量名外面的花括号是可选的,加不加都行,加花括号是为了帮助解释器识别变量的边界,比如下面这种情况:

for hobby in swim pingpang football Java; do
    echo "I am good at ${hobby}."
done

如果不给skill变量加花括号,写成echo "I am good at $skillScript",解释器就会把$skillScript当成一个变量(其值为空),代码执行结果就不是我们期望的样子了。所以我推荐给所有变量加上花括号,这是个好的编程习惯。

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

your_name="tom"
echo $your_name
your_name="alibaba"
echo $your_name

注意,第二次赋值的时候不能写$your_name="alibaba",使用变量的时候才加美元符($)。

只读变量

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

下面的例子尝试更改只读变量,结果报错:

#!/bin/bash
myname="China"
readonly myname
myUrl="America"

运行脚本,执行结果如下:

/bin/sh: NAME: This variable is read only.

删除变量

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

unset variable_name

变量被删除后不能再次使用。unset 命令不能删除只读变量

示例:

#!/bin/sh
myname="China"
unset myname
echo $myname

执行此脚本将没有任何输出。

变量类型

执行Bash脚本时,会同时产生三种变量:

第一种:局部变量 局部变量在脚本或命令中定义,仅在当前Bash实例中有效,其他Bash启动的程序不能访问局部变量。

第二种:环境变量 所有的程序,包括shell启动的程序,都能访问环境变量,有些程序需要环境变量来保证其正常运行。必要的时候Bash脚本也可以定义环境变量。

第三种:Bash变量 Bash变量是由Bash程序设置的特殊变量。Bash变量中有一部分是环境变量,有一部分是局部变量,这些变量保证了Bash脚本的正常运行

3.Bash字符串

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

单引号声明字符串

str='string'

单引号声明字符串的一些限制:

  • 单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
  • 单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行),但可成对出现,作为字符串拼接使用。

 双引号声明字符串

your_name='China'
str="Hello, I know you are \"$your_name\"! \n"
echo -e $str            

输出结果为:

Hello, I know you are "China"! 

双引号的优点:

  • 双引号里可以有变量
  • 双引号里可以出现转义字符

字符串的拼接

your_name="China"
# 使用双引号拼接
greeting="hello, "$your_name" !"
greeting_1="hello, ${your_name} !"
echo $greeting  $greeting_1
# 使用单引号拼接
greeting_2='hello, '$your_name' !'
greeting_3='hello, ${your_name} !'
echo $greeting_2  $greeting_3

输出结果:

hello, runoob ! hello, China !
hello, runoob ! hello, ${your_name} !

通过上述结果可以看出字符串是可以拼接的,单引号内不可以使用已经存在的变量,双引号可以使用其他的变量。
获取字符串长度

string="abcd"
echo ${#string} 

输出:

4

在花括号内使用#可以输出字符串的长度

提取子字符串

以下示例提取从字符串的第3个字符开始截取3个字符:

string="China is very good"
echo ${string:2:3}

输出:

ina

注意:字符串的第一个字符的索引值为0。所以第三个字符所对应的索引值为2。

查找子字符串

 示例:查找字符串中字符h或者a出现的位置(哪一个出现的早就返回哪一个的位置)

string="China"
echo `expr index "$string" ha`  

输出:

注意:上述代码中`是反引号,并不是单引号'。这时候所输出的值并不是索引值了,而是字符串真正的位置。

字符串截取:

Linux 的字符串截取很有用。有八种方法。

假设有变量 var=http://www.aaa.com/123.htm

1. # 号截取,删除左边字符,保留右边字符。

echo ${var#*//}

其中 var 是变量名,# 号是运算符,*// 表示从左边开始删除第一个 // 号及左边的所有字符

即删除 http://

结果是 :www.aaa.com/123.htm

2. ## 号截取,删除左边字符,保留右边字符。

echo ${var##*/}

##*/ 表示从左边开始删除最后(最右边)一个 / 号及左边的所有字符

即删除 http://www.aaa.com/

结果是 123.htm

3. %号截取,删除右边字符,保留左边字符

echo ${var%/*}

%/* 表示从右边开始,删除第一个 / 号及右边的字符

结果是:http://www.aaa.com

4. %% 号截取,删除右边字符,保留左边字符

echo ${var%%/*}

%%/* 表示从右边开始,删除最后(最左边)一个 / 号及右边的字符

结果是:http:

5. 从左边第几个字符开始,及字符的个数

echo ${var:0:5}

其中的 0 表示左边第一个字符开始,5 表示字符的总个数。

结果是:http:

6. 从左边第几个字符开始,一直到结束。

echo ${var:7}

其中的 7 表示左边第8个字符开始,一直到结束。

结果是 :www.aaa.com/123.htm

7. 从右边第几个字符开始,及字符的个数

echo ${var:0-7:3}

其中的 0-7 表示右边算起第七个字符开始,3 表示字符的个数。

结果是:123

8. 从右边第几个字符开始,一直到结束。

echo ${var:0-7}

表示从右边第七个字符开始,一直到结束。

结果是:123.htm

注:(左边的第一个字符是用 0 表示,右边的第一个字符用 0-1 表示)

总结一下就是:

#、## 表示从左边开始删除。一个 # 表示从左边删除到第一个指定的字符;两个 # 表示从左边删除到最后一个指定的字符。

%、%% 表示从右边开始删除。一个 % 表示从右边删除到第一个指定的字符;两个 % 表示从左边删除到最后一个指定的字符。

删除包括了指定的字符本身。

4.Bash数组

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

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

定义一个数组

在 Bash 中,用括号来表示数组,数组元素用"空格"符号分割开。定义数组的一般形式为:

array_name=(value0 value1 value2 value3)

或:

array_name=(
value0
value1
value2
value3
)

还可以单独定义数组的各个分量:

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

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

读取数组

读取数组元素值的一般格式是:

${数组名[下标]}

例如:

valuen=${array_name[n]}

示例:

#!/bin/bash

my_array=(A B "C" D)

echo "第一个元素为: ${my_array[0]}"
echo "第二个元素为: ${my_array[1]}"
echo "第三个元素为: ${my_array[2]}"
echo "第四个元素为: ${my_array[3]}"

 执行脚本,输出结果为:

$ chmod +x test.sh 
$ ./test.sh
第一个元素为: A
第二个元素为: B
第三个元素为: C
第四个元素为: D

获取数组中全部的元素:

使用@ 或 * 可以获取数组中的所有元素,例如:

echo ${array_name[@]}

 示例:

#!/bin/bash


my_array[0]=A
my_array[1]=B
my_array[2]=C
my_array[3]=D

echo "数组的元素为: ${my_array[*]}"
echo "数组的元素为: ${my_array[@]}"

输出结果为:

$ chmod +x test.sh 
$ ./test.sh
数组的元素为: A B C D
数组的元素为: A B C D

获取数组的长度

获取数组长度的方法与获取字符串长度的方法相同,例如:

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

 数组的值也可以写入变量。

示例:

A=1
my_array=($A B C D)
echo "first: ${my_array[0]}"
echo "second: ${my_array[1]}"
echo "third: ${my_array[2]}"
echo "four: ${my_array[3]}"

输出结果为:

first: 1 second: B third: C four: D

循环遍历数组的多种写法:

#!/bin/bash

my_arry=(e f "g","h" abc)
echo "-------FOR循环遍历输出数组--------"
for i in ${my_arry[@]};
do
  echo $i
done

echo "-------::::WHILE循环输出 使用 let i++ 自增:::::---------"
j=0
while [ $j -lt ${#my_arry[@]} ]
do
  echo ${my_arry[$j]}
  let j++
done

echo "--------:::WHILE循环输出 使用 let  "n++ "自增: 多了双引号,其实不用也可以:::---------"
n=0
while [ $n -lt ${#my_arry[@]} ]
do
  echo ${my_arry[$n]}
  let "n++"
done

echo "---------::::WHILE循环输出 使用 let m+=1 自增,这种写法其他编程中也常用::::----------"
m=0
while [ $m -lt ${#my_arry[@]} ]
do
  echo ${my_arry[$m]}
  let m+=1
done

echo "-------::WHILE循环输出 使用 a=$[$a+1] 自增,个人觉得这种写法比较麻烦::::----------"
a=0
while [ $a -lt ${#my_arry[@]} ]
do
 echo ${my_arry[$a]}
 a=$[$a+1]
done

字符串转数组:

#!/bin/bash

words="ii dd kk"

#字符串转数组,空格是分隔符
array=(${words// / })
#打印数组最后一个成员
echo ${array[${#array[*]}-1]}
#打印数组长度
echo ${#array[*]}

#字符串不转换为数组,在循环实现以空格为分隔符打印每个成员
for word in ${words}; do
    echo ${word}
done

结果如下:

kk2iiddkk

5.Bash注释

以 # 开头的行就是注释,会被解释器忽略。

通过每一行加一个 # 号设置多行注释,像这样:

#--------------------------------------------
# 这是一个注释
# author:ubuntu
#--------------------------------------------

如果在开发过程中,遇到大段的代码需要临时注释起来,过一会儿又取消注释,怎么办呢?

每一行加个#符号太费力了,可以把这一段要注释的代码用一对花括号括起来,定义成一个函数,没有地方调用这个函数,这块代码就不会执行,达到了和注释一样的效果。

多行注释

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

:<<EOF
注释内容...
注释内容...
注释内容...
EOF
或
:<<'
注释内容...
注释内容...
注释内容...
'
或
:<<!
注释内容...
注释内容...
注释内容...
!

6.Bash传递参数

我们可以在执行Bash脚本时,向脚本传递参数,脚本内获取参数的格式为:$nn 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推即可

示例:

以下实例我们向脚本传递三个参数,并分别输出,其中 $0 为执行的文件名(包含文件路径):

#!/bin/bash

echo "Shell 传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";

为脚本设置可执行权限,并执行脚本,输出结果如下所示:

$ chmod +x test.sh 
$ ./test.sh 1 2 3
Shell 传递参数实例!
执行的文件名:./test.sh
第一个参数为:1
第二个参数为:2
第三个参数为:3

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

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

echo "Shell 传递参数实例!";
echo "第一个参数为:$1";
echo "参数个数为:$#";
echo "传递的参数作为一个字符串显示:$*";

执行脚本,输出结果:

$ chmod +x test.sh 
$ ./test.sh 1 2 3
Shell 传递参数实例!
第一个参数为:1
参数个数为:3
传递的参数作为一个字符串显示:1 2 3

$* 与 $@ 区别:

  • 相同点:都是引用所有参数。
  • 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 " * " 等价于 "1 2 3"(传递了一个参数),而 "@" 等价于 "1" "2" "3"(传递了三个参数)。
#!/bin/bash

echo "-- \$* 演示 ---"
for i in "$*"; do
    echo $i
done

echo "-- \$@ 演示 ---"
for i in "$@"; do
    echo $i
done

输出:

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

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值