什么是Bash?
1.bash简介
Bash(GNU Bourne-Again Shell)是一个为GNU计划编写的Unix shell,它是许多Linux平台默认使用的shell。
shell是一个命令i解释器,是介于操作系统内核与用户之间的一个绝缘层。准确地说,它也是能力很强的计算机语言,被称为解释性语言或脚本语言。它可以通过将系统调用、公共程序、工具和编译过的二进制程序”粘合“在一起来建立应用,这是大多数脚本语言的共同特征,所以有时候脚本语言又叫做“胶水语言” 事实上,所有的UNIX命令和工具再加上公共程序,对于shell脚本来说,都是可调用的。Shell脚本对于管理系统任务和其它的重复工作的例程来说,表现的非常好,根本不需要那些华而不实的成熟紧凑的编译型程序语言。
初步练习
1.Hello World
Bash之Hello World
$ vim hello.sh
使用vim编辑hello.sh ,输入如下代码并保存:
#!/bin/bash
# This is a comment
echo Hello World
运行Bash脚本的方式:
# 使用shell来执行
$ sh hello.sh
# 使用bash来执行
$ bash hello.sh
还可以让脚本本身就具有可执行权限,通过chmod命令可以修改:
# 赋予脚本的所有者该执行权限,允许该用户执行该脚本
$ chmod u+rx hello.sh
# 执行命令,这将使用脚本第一行指定的shell来执行,如果指定shell不存在,将使用系统默认shell来执行
$ ./hello.sh
利用bash编程可以有效的提高工作效率,避免重复输入命令,比如上传github的bash脚本
cd ~/data/whuhan2013.github.io/
git add .
git commit -m 'update'
git push origin master
expect实现ssh登录脚本
安装expect:brew install expect
代码
#!/usr/bin/expect
spawn ssh root@192.168.22.194
expect "*password:"
send "123\r"
expect "*#"
interact
参考链接:expect详解
bash中的特殊字符
一、#符号
1.#注释
转意后的#不能作为注释使用
二、分号(;)
1.命令分隔符
使用分号(;)可以在同一行上写两个或两个以上的命令。
2.终止case选项(双分号)
使用双分号(;;)可以终止case选项。
三、点号(.)
1.等价于 source 命令
bash 中的 source 命令用于在当前 bash 环境下读取并执行 FileName.sh 中的命令。
四、引号
1.双引号(”)
“STRING” 将会阻止(解释)STRING中大部分特殊的字符。
2.单引号(’)
‘STRING’ 将会阻止STRING中所有特殊字符的解释,这是一种比使用”更强烈的形式。
五、斜线和反斜线
1.斜线(/)
文件名路径分隔符。分隔文件名不同的部分(如/home/bozo/projects/Makefile)。也可以用来作为除法算术操作符。
2.反斜线(\)
一种对单字符的引用机制。\X 将会“转义”字符X。这等价于”X”,也等价于’X’。\ 通常用来转义双引号(”)和单引号(’),这样双引号和单引号就不会被解释成特殊含义了。
六、反引号(`)
1.命令替换
command 结构可以将命令的输出赋值到一个变量中去。在后边的后置引用(backquotes)或后置标记(backticks)中也会讲解。
反引号中的命令会优先执行
$ cp `mkdir back` test.sh back
$ ls
先创建了 back 目录,然后复制 test.sh 到 back 目录
七、冒号(:)
1.空命令
等价于“NOP”(no op,一个什么也不干的命令)。也可以被认为与shell的内建命令true作用相同。“:”命令是一个bash的内建命令,它的退出码(exit status)是(0)。
2.变量扩展/子串替换
在与>重定向操作符结合使用时,将会把一个文件清空,但是并不会修改这个文件的权限。如果之前这个文件并不存在,那么就创建这个文件。
$ : > test.sh # 文件“test.sh”现在被清空了
# 与 cat /dev/null > test.sh 的作用相同
# 然而,这并不会产生一个新的进程, 因为“:”是一个内建命令
在与»重定向操作符结合使用时,将不会对预先存在的目标文件(: » target_file)产生任何影响。如果这个文件之前并不存在,那么就创建它。
也可能用来作为注释行,但不推荐这么做。使用 # 来注释的话,将关闭剩余行的错误检查,所以可以在注释行中写任何东西。然而,使用 : 的话将不会这样。
”:”还用来在 /etc/passwd 和 $PATH 变量中做分隔符,如:
八、问号(?)
1.测试操作符
在一个双括号结构中,? 就是C语言的三元操作符,如:
九、美元符号($)
1.变量替换
2.命令替换(同反引号)
bash中的特殊字符(下)
一、小括号(( ))
1.命令组
在括号中的命令列表,将会作为一个子 shell 来运行。
在括号中的变量,由于是在子shell中,所以对于脚本剩下的部分是不可用的。父进程,也就是脚本本身,将不能够读取在子进程中创建的变量,也就是在子shell 中创建的变量
2.初始化数组
二、大括号({ })
1.文件名扩展
注意: 在大括号中,不允许有空白,除非这个空白被引用或转义。
2.代码块
代码块,又被称为内部组,这个结构事实上创建了一个匿名函数(一个没有名字的函数)。然而,与“标准”函数不同的是,在其中声明的变量,对于脚本其他部分的代码来说还是可见的。
三、中括号([ ])
1.条件测试
条件测试表达式放在[ ]中。值得注意的是[是shell内建test命令的一部分,并不是/usr/bin/test中的外部命令的一个链接。
双中括号([[ ]])也用作条件测试(判断),后面的实验会详细讲解。
2.数组元素
在一个array结构的上下文中,中括号用来引用数组中每个元素的编号。
四、尖括号(< 和 >)
1.重定向
test.sh > filename 重定向test.sh的输出到文件 filename 中。如果 filename 存在的话,那么将会被覆盖。
test.sh &> filename 重定向 test.sh 的 stdout(标准输出)和 stderr(标准错误)到 filename 中。
test.sh >&2 重定向 test.sh 的 stdout 到 stderr 中。
test.sh >> filename 把 test.sh 的输出追加到文件 filename 中。如果filename 不存在的话,将会被创建。
五、竖线( | ) |
管道
分析前边命令的输出,并将输出作为后边命令的输入。这是一种产生命令链的好方法。
六、破折号(-)
1.选项,前缀
在所有的命令内如果想使用选项参数的话,前边都要加上“-”。
2.用于重定向stdin或stdout
变量和参数
一、变量替换
1.概念
变量的名字就是变量保存值的地方。引用变量的值就叫做变量替换。
如果 variable 是一个变量的名字,那么 $variable 就是引用这变量的值,即这变量所包含的数据。
$variable 事实上只是 ${variable} 的简写形式。在某些上下文中 $variable 可能会引起错误,这时候你就需要用 ${variable} 了。
二、变量赋值
1.说明
赋值操作前后都不能有空白。
因为 = 和 -eq 都可以用做条件测试操作,所以不要与这里的赋值操作相混淆。
注意: = 既可以用做条件测试操作,也可以用于赋值操作,这需要视具体的上下文而定。bash中==也可作为条件判断。
三、变量不区分类型
1.说明
与大多数编译型语言不同,Bash并不区分变量的”类型”。本质上,Bash变量都是字符串。但是依赖于具体的上下文,Bash也允许比较操作和整数操作。其中的关键因素就是,为变量赋的值是否只有数字。
引用和转义
1.介绍
在一个双引号中通过直接使用变量名的方法来引用变量,一般情况下都是没问题的。这么做将阻止所有在引号中的特殊字符被重新解释(即都被当作普通的字符串),包括变量名,但是 $、`(后置引用)和 “"(转义符)除外。
保留 $ 作为特殊字符的意义是为了能够在双引号中也能够正常的引用变量(”$variable”)。
使用双引号还能够阻止单词分割,即使这个参数包含有空白,单词也不会被分隔开。 如 variable1=”a variable containing five words”
IFS(Internal Field Seperator)在Linux的shell中预设的分隔符。IFS是shell脚本中的一个重要概念,在处理文本数据时,它是相当有用的。内部字段分隔符是用于特定用途的定界符。IFS是存储定界符的环境变量,它是当前shell环境使用的默认定界字符串。
当我们设置了bash内置变量IFS后,再使用echo输出时,会将所设定的字符用空格去代替。
单引号(’ ‘)操作与双引号基本一样,但是不允许引用变量,因为 $ 的特殊意义将被关闭。
在单引号中,任何特殊字符都按照字面的意思进行解释,除了单引号本身。所以说单引号(全引用)是一种比双引号(部分引用)更严格的引用方法。
二、转义
1.概念
转义是一种引用单个字符的方法。一个前面放上转义符(\)的字符就是告诉shell 这个字符按照字面的意思进行解释,换句话说,就是这个字符失去了它的特殊含义。
退出和退出状态码
一、退出状态码
1.退出
exit 被用来结束一个脚本,它也返回一个值,并且这个值会传递给脚本的父进程,父进程会使用这个值做下一步的处理。
2.退出状态码
每个命令都会返回一个退出状态码(有时候也被称为返回状态)。
成功的命令返回 0,不成功的命令返回非零值,非零值通常都被解释成一个错误码。行为良好的UNIX命令、程序和工具都会返回 0 作为退出码来表示成功,虽然偶尔也会有例外。
同样的,脚本中的函数和脚本本身也会返回退出状态码。在脚本或者是脚本函数中执行的最后的命令会决定退出状态码。在脚本中,exit nnn 命令将会nnn退出码传递给shell(nnn必须是十进制数,范围必须是0-255)。
当脚本以不带参数的exit命令来结束时,脚本的退出状态码就由脚本中最后执行的命令来决定(就是 exit 之前的命令)。
$? 指代的是上一条指令的执行结果
条件判断
一、条件测试结构
1.if/then 结构
if/then 结构用来判断命令列表的退出状态码是否为 0,因为0表示成功,如果成功的话,这里应该那么就执行接下来的一个或多个命令。
注意: 这里与C语言的等其它语言不同,不能直接使用0或者1作为判断条件,而应该以false,true代替。以其它大多数语言相反的true返回的是0,false返回的是1
有一个专有命令 [ (左中括号,特殊字符)。这个命令与test命令等价,由于效率上的考虑,bash将它作为一个内建命令。
注意: 由于bash的语法检查机制,如果在条件测试时只使用一个[将会出现一个错误提示,为了避免这个问题,我们通常将使用一对方括号包含条件测试[]
在版本2.02的Bash中, 引入了 “[[ … ]]” 扩展测试命令,[[ 是一个关键字,并不是一个命令。
if 命令能够测试任何命令,并不仅仅是中括号中的条件。
二、文件测试操作符
操作符 说明
-e 文件存在
-a 文件存在,这个选项的效果与 -e 相同。但是它已经被“弃用”了,并且不鼓励使用。
-f 表示这个文件是一个一般文件(并不是目录或者设备文件)
-s 文件大小不为零
-d 表示这是一个目录
-b 表示这是一个块设备(软盘,光驱,等等)
-c 表示这是一个字符设备(键盘,modem,声卡,等等)
-p 这个文件是一个管道
-h 这是一个符号链接
-L 这是一个符号链接
-S 表示这是一个socket
-t 文件(描述符)被关联到一个终端设备上,这个测试选项一般被用来检测脚本中的 stdin([ -t 0 ]) 或者 stdout([ -t 1 ])是否来自于一个终端
-r 文件是否具有可读权限(指的是正在运行这个测试命令的用户是否具有读权限)
-w 文件是否具有可写权限(指的是正在运行这个测试命令的用户是否具有写权限)
-x 文件是否具有可执行权限(指的是正在运行这个测试命令的用户是否具有可执行权限)
三、二元比较操作符
1.整数比较
-eq 等于
if [ "$a" -eq "$b" ]
-ne 不等于
if [ "$a" -ne "$b" ]
-gt 大于
if [ "$a" -gt "$b" ]
-ge 大于等于
if [ "$a" -ge "$b" ]
-lt 小于
if [ "$a" -lt "$b" ]
-le 小于等于
if [ "$a" -le "$b" ]
< 小于(在双括号中使用)
(("$a" < "$b"))
<= 小于等于(在双括号中使用)
(("$a" <= "$b"))
大于(在双括号中使用)
(("$a" > "$b"))
= 大于等于(在双括号中使用)
(("$a" >= "$b"))
2.字符串比较
= 等于
if [ "$a" = "$b" ]
== 等于,与=等价
if [ "$a" == "$b" ]
!= 不等号
if [ "$a" != "$b" ]
< 小于,按照ASCII字符进行排序
if [[ "$a" < "$b" ]]
if [ "$a" \< "$b" ]
注意"<"使用在[ ]结构中的时候需要被转义
大于,按照ASCII字符进行排序
if [[ "$a" > "$b" ]]
if [ "$a" \> "$b" ]
注意“>”使用在[ ]结构中的时候需要被转义
-z 字符串为“null”,意思就是字符串长度为零 -n 字符串不为“null”