赞
踩
目录
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软件
打开终端,通过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 系统是另外开设了一个进程来运行的。
接下来我们就先看看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脚本的正常运行
字符串是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 表示)
总结一下就是:
#、## 表示从左边开始删除。一个 # 表示从左边删除到第一个指定的字符;两个 # 表示从左边删除到最后一个指定的字符。
%、%% 表示从右边开始删除。一个 % 表示从右边删除到第一个指定的字符;两个 % 表示从左边删除到最后一个指定的字符。
删除包括了指定的字符本身。
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
以 # 开头的行就是注释,会被解释器忽略。
通过每一行加一个 # 号设置多行注释,像这样:
- #--------------------------------------------
- # 这是一个注释
- # author:ubuntu
- #--------------------------------------------
如果在开发过程中,遇到大段的代码需要临时注释起来,过一会儿又取消注释,怎么办呢?
每一行加个#符号太费力了,可以把这一段要注释的代码用一对花括号括起来,定义成一个函数,没有地方调用这个函数,这块代码就不会执行,达到了和注释一样的效果。
多行注释
多行注释还可以使用以下格式:
- :<<EOF
- 注释内容...
- 注释内容...
- 注释内容...
- EOF
- 或
- :<<'
- 注释内容...
- 注释内容...
- 注释内容...
- '
- 或
- :<<!
- 注释内容...
- 注释内容...
- 注释内容...
- !
我们可以在执行Bash脚本时,向脚本传递参数,脚本内获取参数的格式为:$n。n 代表一个数字,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
$* 与 $@ 区别:
- #!/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
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。