0、简介
Bash(GNU Bourne-Again Shell)是一个为 GNU 计划编写的 Unix shell,它是许多 Linux 平台默认使用的 shell。
shell 是一个命令解释器,是介于操作系统内核与用户之间的一个绝缘层。准确地说,它也是能力很强的计算机语言,被称为解释性语言或脚本语言。它可以通过将系统调用、公共程序、工具和编译过的二进制程序”粘合“在一起来建立应用,这是大多数脚本语言的共同特征,所以有时候脚本语言又叫做“胶水语言”。
事实上,所有的 UNIX 命令和工具再加上公共程序,对于 shell 脚本来说,都是可调用的。Shell 脚本对于管理系统任务和其它的重复工作的例程来说,表现的非常好,根本不需要那些华而不实的成熟紧凑的编译型程序语言。
特殊字符
# 注释.
; 命令分隔符,可以在同一行上写两个或两个以上的命令.
;; 终止case选项.
. "点"命令等价于source命令.
"点"作为文件名的一部分. 如果点放在文件名的开头的话, 那么这个文件将会成为隐藏文件,
"点"字符匹配. "点"用来匹配任何的单个字符.
"" 部分引用[双引号, 即"]. "STRING"将会阻止(解释)STRING中大部分特殊的字符.
'' 全引用[单引号, 即']. 'STRING'将会阻止STRING中所有特殊字符的解释. 这是一种比使用"更强烈的形式.
, 逗号操作符. 逗号操作符链接了一系列的算术操作. 虽然里边所有的内容都被运行了,但只有最后一项被返回.
\ 转义符[反斜线, 即\]. 一种对单字符的引用机制.
/ 文件名路径分隔符[斜线, 即/],也可以用来作为除法算术操作符.
`` 命令替换. 已逐渐被$()替代,后者更灵活,如可以嵌套等
: 空命令[冒号, 即:]. 也可以被认为与shell的内建命令true作用相同.
! 取反操作符[叹号, 即!].
* 通配符[星号, 即*]. *可以用来做文件名匹配,也可以用在正则表达式中, 用来匹配任意个数(包含0个)的字符.
算术操作符. 在算术操作符的上下文中, *号表示乘法运算.
如果要做求幂运算, 使用**, 这是求幂操作符.
? 测试操作符. 在一个特定的表达式中, ?用来测试一个条件的结果.
在一个双括号结构中, ?就是C语言的三元操作符.
在参数替换表达式中, ?用来测试一个变量是否被set了.
通配符. ?在通配(globbing)中, 用来做匹配单个字符的"通配符".
$ 变量替换(引用变量的内容).
行结束符. 在正则表达式中, "$"表示行结束符.
${} 参数替换.
$* 位置参数
$@ 同上.
$? 退出状态码变量. $?变量保存了一个命令, 一个函数, 或者是脚本本身的退出状态码.
$$ 进程ID变量. 这个$$变量保存了它所在脚本的进程ID.
() 命令组.
{} 代码块,又被称为内部组, 这个结构事实上创建了一个匿名函数(一个没有名字的函数).
[] 条件测试.数组元素.用作正则表达式的一部分, 方括号描述一个匹配的字符范围.
[[]] 测试.
(()) 整数扩展.
>
&>
>&
>>
<
<> 重定向.
<< 用在here document中的重定向.http://doc.linuxpk.com/doc/abs/here-docs.html#HEREDOCREF
<<< 用在here string中的重定向.
<
> ASCII comparison.
\<
\> 正则表达式中的单词边界.
| 管道.
>| 强制重定向(即使设置了noclobber选项 -- 就是-C选项). 这将强制的覆盖一个现存文件.
|| 或-逻辑操作.
& 后台运行命令.
&& 与-逻辑操作.
- 选项, 前缀.
用于重定向stdin或stdout[破折号, 即-].
先前的工作目录.
减号. 减号属于算术操作.
= 等号. 赋值操作,"="也用来做字符串比较操作.
+ 加号. 加法算术操作.某些命令内建命令使用+来打开特定的选项, 用-来禁用这些特定的选项.
% 取模. %也是一种模式匹配操作. 在BASH中,%number表示将后台编号为number的任务调度到前台执行。
~ home目录[波浪号, 即~].
~+ 当前工作目录. 相当于$PWD内部变量.
~- 先前的工作目录. 相当于$OLDPWD内部变量.
=~ 正则表达式匹配. 这个操作将会在version 3版本的Bash部分进行讲解.
^ 行首. 在正则表达式中, "^"表示定位到文本行的行首.
1、创建
可以使用vi创建一个*.sh的文件,然后编写以下代码
#!/bin/bash
echo 'hello world'
运行
#方式1
sh test.sh
#方式2
bash test.sh
#方式3,设置文件为可执行文件,然后执行
chmod +x test.sh
./test.sh
这样第一个脚本文件就完成了
2、变量
变量的声明方式和使用如下
#声明
var=value
#调用
$var
参考代码
#!/bin/bash
var='hello world'
echo $var
declare用法
# 声明变量 VARIABLE,并赋予其踪迹属性
declare -t VARIABLE=value
-r 只读
-i 整型
-a 数组
-f 函数
-x export 这句将会声明一个变量, 并作为这个脚本的环境变量被导出.
-x var=$value 允许在声明变量类型的同时给变量赋值.
3、参数
你可以向 Bash 脚本传递参数,格式如下
./test.sh arg1 arg2 ... argn
在脚本中,你可以使用 $1
来代表第 1 个参数,用 $2
来代表第 2 个参数,以此类推。$0
是一个特殊变量,它代表正在运行的脚本的名字。
#!/bin/bash
var='hello world'
echo $var
echo 'script is:' $0
echo 'arg1 is:' $1
echo 'arg2 is:' $2
其他特殊变量
特殊变量 | 描述 |
---|---|
$0 | 脚本名称 |
$1、$2…$9 | 脚本参数 |
${n} | 10 到 255 的脚本参数 |
$# | 参数数量 |
$@ | 所有参数一起 |
$$ | 当前 shell 的进程 id |
$! | 最后执行命令的进程 id |
$? | 最后执行命令的退出状态 |
除了直接传参外,还可以通过read命令接受键盘输入
#!/bin/bash
var='input a value'
echo $var
read value
echo 'the arg is:' $value
除echo 外,read命令可以通过 -p 直接提示
#!/bin/bash
var='input a value'
#echo $var
read -p "$var" value
echo 'the arg is:' $value
4、运算
Bash Shell 中执行算术运算的语法
$((arithmetic_operation))
Bash 算术运算符
操作符 | 描述 |
---|---|
+ | 加法 |
– | 减法 |
* | 乘法 |
/ | 整数除法 结果取整,没有小数。 如果要进行浮点数运算,需要这样使用 bc 命令 |
% | 模运算(取余) |
** | 指数(a 的 b 次方) |
示例
#!/bin/bash
read -p 'input num1:' num1
read -p 'input num2:' num2
result1=$(($num1+$num2))
result2=$(($num1-$num2))
result3=$(($num1*$num2))
result4=$(($num1/$num2))
result5=$(echo "$num1/$num2" | bc -l)
echo 'result1 is:' $result1
echo 'result2 is:' $result2
echo 'result3 is:' $result3
echo 'result4 is:' $result4
echo 'result5 is:' $result5
5、数组
Bash 数组用来存储同一类型的值,和大多数其他的编程语言一样,数组的索引从 0 开始。
#!/bin/bash
#声明,通过空格分隔元素
arr=(this is a array)
#调用
echo ${arr[0]}
#显示所有
echo ${arr[*]}
#获取数组长度
echo ${#arr[@]}
6、字符串
#!/bin/bash
#声明
str="this is a str"
str2="+str2"
#获取字符串长度
echo ${#str}
echo ${#str2}
#连接字符串
echo $str+$str2
#截取字符串 字符串:开始位置:截取长度
echo ${str:0:4}
#替换 字符串/查找值/替换值
echo ${str2/+/=}
#删除 字符串/需要删除的值
echo ${str2/+}
7、条件语句
可以通过使用 if
或 if-else
语句为你的 Bash 脚本添加条件逻辑。这些语句以 fi
结束。
if基本语法
if [ condition ]; then
your code
#可选
elif [ expression ]; then
your code
#可选
else
your code
fi
注意使用 [ ... ];
和 then
。
#!/bin/bash
read -p 'input a num:' num
result=$(($num % 2))
if [ $result -eq 0 ]; then
echo $num ' is even'
else
echo $num ' is odd'
fi
case结构
case variable in
value1)
command1
;;
value2)
command2
;;
*)
command3
;;
esac
cat << ENDIT
1)one
2)two
ENDIT
read choice;
case "$choice" in
1)
echo "one"
;;
2)
echo "two"
;;
*)
echo "Error"
;;
esac
条件操作符
条件 | 当…时,等同于 true |
---|---|
$a -lt $b | $a < $b ($a 是小于 $b) |
$a -gt $b | $a > $b ($a 是大于 $b) |
$a -le $b | $a <= $b ($a 是小于或等于 $b) |
$a -ge $b | $a >= $b ($a 是大于或等于 $b) |
$a -eq $b | $a == $b ($a 等于 $b) |
$a -ne $b | $a != $b ($a 不等于 $b) |
字符串比较
条件 | 当…时,等同于 true |
---|---|
“$a” = “$b” | $a 等同于 $b |
“$a” == “$b” | $a 等同于 $b |
“$a” != “$b” | $a 不同于 $b |
“$a” > “$b” | 大于, 按照ASCII字符进行排序 |
“$a” < “$b” | 小于, 按照ASCII字符进行排序 |
-z “$a” | $a 是空的 |
-n “$a” | $a 不为空 |
-l “$a” | $a 的长度 |
检查文件类型
条件 | 当…时,等同于 true |
---|---|
-f $a | $a 是一个文件 |
-d $a | $a 是一个目录 |
-L $a | $a 是一个链接 |
f1 -nt f2 | 文件f1比文件f2新 |
f1 -ot f2 | 文件f1比文件f2旧 |
f1 -ef f2 | 文件f1和文件f2是相同文件的硬链接 |
检查文件
-e 文件存在.
-f 表示这个文件是一个一般文件.
-d 表示这是一个目录.
-b 表示这是一个块设备.
-c 表示这是一个字符设备.
-p 这个文件是一个管道
-s 文件大小不为零.
-L 这是一个符号链接
-S 表示这是一个socket
-t 文件(描述符)被关联到一个终端设备上.
这个测试选项一般被用来检测脚本中的stdin([ -t 0 ]) 或者stdout([ -t 1 ])是否来自于一个终端.
-r 文件是否具有可读权限(指的是正在运行这个测试命令的用户是否具有读权限)
-w 文件是否具有可写权限(指的是正在运行这个测试命令的用户是否具有写权限)
-x 文件是否具有可执行权限(指的是正在运行这个测试命令的用户是否具有可执行权限)
-g set-group-id(sgid)标记被设置到文件或目录上
-u set-user-id (suid)标记被设置到文件上
-k 设置粘贴位
-O 判断你是否是文件的拥有者
-G 文件的group-id是否与你的相同
-N 从文件上一次被读取到现在为止, 文件是否被修改过
! "非" -- 反转上边所有测试的结果(如果没给出条件, 那么返回真).
逻辑运算
条件 | 说明 |
---|---|
-a | 逻辑与 |
-o | 逻辑或 |
! | 逻辑非 |
要特别注意空格。开括号和闭括号、条件之间必须有空格。同样地,条件操作符(-le
、==
等)之前和之后必须有空格。
8、循环语句
Bash 支持三种类型的循环:for
、while
和 until
。
for语法
#!/bin/bash
for num in {1..10}; do
echo $num
done
while语法
#!/bin/bash
num=1
while [ $num -le 10 ]; do
echo $num
num=$(($num+1))
done
until语法
#!/bin/bash
num=1
until [ $num -gt 10 ]; do
echo $num
num=$(($num+1))
done
9、函数
基本语法
function_name() {
commands
}
$1-9 1-9个参数
$# 参数的数量
$@ 所有参数,但是所有参数都是一个字符串
$* 所有参数,但每个参数都是一个单独元素
#!/bin/bash
sum() {
sum=$(($1+$2))
echo "The sum of $1 and $2 is: $sum"
}
echo "Let's use the sum function"
sum 1 5