shell是用C语言编写的程序,为用户与Linux之间的桥梁。但是,本篇文章中的shell是指shell脚本语言。
话不多说,先上个例子。脚本 test.sh 如下:
#!/bin/bash
#打印出Hello,World
echo "Hello,World"
说明1. #! 是一个约定的标记,用来告诉系统该脚本需要什么解释器来执行,如 #!/bin/sh #!/bin/bash
说明2. 第二行是注释,shell中的注释使用 #
执行shell脚本的两种方法:
1. 可执行程序
chmod +x ./test.sh #使脚本具有执行权限
./test.sh #执行脚本
2. 作为解释器参数执行
/bin/sh test.sh (可以简写为 sh test.sh)
二、shell变量
2.1 shell变量命名规则
1)只能用英文字母、数字和下划线,且首字母不能以数字开头;
2)中间不能有空格、标点符号等其他符号;
3)不能使用bash的保留关键字
2.2 shell变量定义和使用
定义语法: varname=值
注意: =号前后不能有空格
使用变量语法: $varname
也可以使用 ${varname} , {} 为可选项,界定变量名边界
2.3 只读变量
使用 readonly 命令修饰的变量,值不可变,称只读变量。如
readonly varname="test.sh"
2.4 删除变量
使用 unset 命令可以删除非只读变量。如
varname=11
unset varname
2.5 shell中同时存在三种变量
1) 局部变量
2)环境变量
3)shell变量
三、shell中数据结构
3.1 字符串
1)可以使用单引号、双引号,也可以不使用引号
单引号:1.包含的字符串会原样输出;2.包含的字符串不能出现单独一个单引号
双引号:1.包含的字符串可以出现变量;2.可以有转义符
2)定义一个字符串: str=abcd
3)获取字符串的长度: ${#str}
4)提取子字符串: ${#str:first:length} #从first位置起截取length长度的字符串
5)查找子字符串: `expr index "$str" io` #使用反引号`
3.2 shell数组
shell只支持一维数组,并且不限定数组的大小,数组的下标是从0开始的,下标可以是整数或算术表达式,其值应该大于或者等于0.
1)数组的定义: shell中使用括号()定义数组,元素之间用“空格”分隔,语法如下
array_name=(value0 value1 value2 ......... valueN)
也可以使用下标来定义: array_name[下标]=value
2)读取数组 语法: ${array_name[下标]} #下标为@或者*表示所有元素
3)获取数组长度: 与获取字符串长度的方法相同
获取数组元素个数: ${#array_name[@]} 或者 ${#array_name[*]}
获取单个元素的长度: ${#array_name[下标]}
四、shell注释
单行注释: #
多行注释: :<<EOF
.........
.........
EOF
或者
:<<!
...............
...............
!
五、shell基本运算符
包括 算数运算符、关系运算符、布尔运算符、字符串运算符、文件测试运算符。
5.1 算数运算符
原生Bash不支持简单的数字运算,但可以使用其他命令实现,如awk和expr,其中expr最常用
例如: val=`expr 2 + 2`
注意1:表达式和运算符之间必须有空格;
注意2:必须使用``(反引号)包含
算数运算符及其说明和举例
+ : 加法, `expr $a + $b`
- : 减法
* : 乘法
/ : 除法
% : 取余
= : 赋值, a=$b
== : 相等, [$a == $b]
!= : 不相等
5.2 关系运算符
只支持数字和值为数字的字符串
关系运算符及其说明和举例
-eq : 是否相等, [$a -eq $b]
-nq : 是否不相等, [$a -nq $b]
-gt : 大于, [$a -gt $b]
-lt : 小于, [$a -lt $b]
-ge : 大于等于, [$a -ge $b]
-le : 小于等于, [$a -le $b]
5.3 布尔运算符
布尔运算符及其说明和举例
! : 非, [!false]
-o : 或,[$a -lt 20 -o $b -gt 100]
-a : 与,[$a -lt 20 -a $b -gt 100]
5.4 逻辑运算符
逻辑运算符及其说明和举例
&& : 逻辑的AND, [[$a -lt 20 && $b -gt 100]]
|| : 逻辑的OR,[[$a -lt 20 || $b -gt 100]]
5.5 字符串运算符
字符串运算符及其说明和举例
= : 是否相等,相等为true, [ $a = $b ]
!= : 是否不相等,不相等为true, [ $a != $b ]
-z : 长度是否为0,0为true, [ -z $a ]
-n : 长度是否为0,不为0为true, [ -n $a ]
: 是否为空,不为空返回true, [ $a ]
5.6 文件测试运算符
用于检测unix文件的各种属性
文件测试运算符及其说明和举例
-b file : 检测文件是否是块设备文件,是返回true, [ -b file ]
-c file : 是否是字符设备文件,是返回true
-d file : 是否是目录,是返回true
-f file : 是否是普通文件,是返回true
-g file : 是否设置了SGID位,是返回true
-k file : 是否设置了粘着位(sticky Bit),是返回true
-p file : 是否是有名管道,是返回true
-u file : 是否设置了SUID位,是返回true
-r file : 文件是否可读,是返回true
-w file : 文件是否可写,是返回true
-x file : 文件是否可执行,是返回true
-s file : 文件是否为空,不为空返回true
-e file : 文件(目录)是否存在,是返回true
5.7 test命令
用于检查某个条件是否成立,可以进行数值、字符和文件三个方面的测试。与上面的“关系运算符”、“字符串运算符”、“文件测试运算符”相同,只是写法上不同。
test命令写法如下:
test ${num1} -eq ${num2}
六、shell打印命令
shell打印命令有 echo 和 printf
6.1 shell echo命令
用于字符串的输出,格式 : echo str
显示普通字符串: echo "It is a test"
显示转移字符: echo ""It is a test""
显示变量: echo $str
开启转义: echo -e "OK! " #换行
echo -e "OK! c" #不换行
单引号'' 与 双引号"" 的区别
单引号:原样输出;双引号:变量、转义符等均生效。
显示命令执行结果: echo `date` #注意是反引号
echo总结
名称 | 能否引用变量 | 能否引用转义符 | 能否引用文本格式符(换行、制表等符号)
单引号 | 否 | 否 | 否
双引号 | 能 | 能 | 能
无引号 | 能 | 能 | 否
6.2 printf 命令
相较于 echo ,printf 具有很好的移植性,但是printf不会自动添加换行符,需要手动添加
printf命令的语法: printf format-string [arguments ......]
说明1: format-string 格式控制字符串
说明2: arguments 参数列表
例如: printf "%-10s %-8s %-4s " 姓名 性别 体重kg
printf格式替换符: %d %s %c %f
d : Decimal 十进制整数
s : String 字符串
c : char 字符
f : Float 浮点数
printf的转义序列:
a : 警告字符;
: 后退
c :
f : 换页
: 换行
: 回车
: 水平制表符
v : 垂直制表符
\ : 一个字面上的反斜杠字符
ddd : 表示 1 到 3 位数八进制值的字符,仅在格式字符串中有效
ddd : 表示 1 到 3 位的八进制值字符
七、read 命令
read命令从标准输入中读取一行,并把输入行的每个字段的值指定给shell变量。read命令一个一个词组地接收输入的参数,之间用空格分隔,输入的词大于需要参数的个数,则最后多余的会成一个整体
read 参数说明:
-p : 输入提示文字
-n : 输入字符长度限制
-t : 输入限时
-s : 隐藏输入内容
八、shell流程控制
首先声明一点,shell控制流中不能为空。
8.1 if
格式:
if condition
then
command1
...........
commandn
fi
8.2 if else
格式:
if condition
then
command1
..........
commandn
else
command1
..........
commandn
fi
8.3 if else-if else
格式:
if condition
then
command1
.........
commandn
elif condition
then
command1
.........
commandn
.........
.........
else
command1
..........
commandn
fi
8.4 for循环
格式:
for var in 列表
do
command1
..........
commandn
done
或者
for((assignment; condition; next))
do
command1
.........
commandn
done
8.5 while结构
格式:
while condition
do
command1
...........
commadn
done
8.6 无限循环
格式:
while :
do
command1
..........
commandn
done
或者
while true
do
command1
........
commandn
done
或者
for((;;))
do
command1
..........
commandn
done
8.7 until循环
until循环只有条件为fasle才执行,条件为true则终止执行。与while刚好相反。
格式:
until condition
do
command1
............
commandn
done
8.8 shell中的break 和 continue
用于退出循环,用法跟java语言中相同。
8.9 case多选择语句
匹配一个值与一个模式,如果匹配成功,执行相匹配的命令
格式:
case 值 in
模式1)
command1
...........
commandn
模式2)
command1
...........
commandn
..............
..............
模式n)
command1
...........
commandn
*)
command1
...........
commandn
esac
九、shell函数
格式:
[function] funname[()]
{
astion;
[return int;]
}
注意:1. 调用函数时直接使用函数名 funname;2. return后跟数值;如果没有显示return则将最后一条命令的运行结果作为返回值;3. 调用函数之后,用 $? 来获取函数返回值;4. 函数调用必须在使用后;5. 可以使用函数传参,函数中获取参数的方式为 $n (n >= 1,且n < 10时可以省去{})。
十、shell传递参数
执行shell脚本或者调用shell函数时,可以向脚本或者函数传递参数。
在脚本中使用 $n 获取参数,$n 表示第n个参数,其中 n 为大于0的整数。
10.1 特殊参数
$0 : 所执行脚本的文件名;
$# : 传递到脚本的参数个数;
$* : 以一个单字符串显示所有向脚本传递的参数;
$$ : 脚本运行的当前进程ID号;
$! : 后台运行的最后一个进程的ID号;
$@ : 与 $* 相同,但是使用时加引号,并在引号中返回每个参数;
$- : 显示shell使用的当前选项;
$? : 显示最后命令的退出状态,0表示正确退出,其他值表示错误。
10.2 $* 与 $@ 区别
相同点: 都是引用所有参数;
不同点: 只有在双引号中体现出来, * 号: "1 2 3", @: "1" "2" "3"
十一、shell输入/输出重定向
标准输入/标准输出 : 默认输入/输出为终端
重定向命令列表如下:
命令 | 说明
command > filename | 将输出重定向到filename
command < filename | 将输入重定向到fielname
command >> filename | 将输出以追加的方式重定向到filename
n > filename | 将文件描述符为n的文件重定向到filename
n >> filename | 将文件描述符为n的文件以追加的方式重定向到filename
n >& m | 将输出文件m 和 n合并
n <& m | 将输入文件m 和 n合并
<< tag | 将开始标记tag和结束标记tag之间的内容作为输入
n的取值: 0 (标准输入); 1 (标准输出); 2 (标准错误输出)
11.1 Here Document
shell中的一种特殊的重定向方式,用来将输入重定向到一个交互式shell脚本或程序
格式:
command << delimiter
document
delimiter
作用是将两个delimiter之间的内容document作为输入传递给command
注意:结尾的delimiter前后不能有任意的其他字符
例如:
cat << EOF
"It is a test"
EOF
11.2 /dev/null 文件
写入该文件中内容会被丢弃;从该文件中也读不出任何内容。
十二、shell文件包含
shell可以包含外部的脚本。
格式:
. filename #注意点号(.)和文件名中间有一个空格
或者
source filename
注意:被包含的文件不需要可执行权限。