0 shell简介
Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。
Shell 既是一种命令语言,又是一种程序设计语言。
Shell 脚本(shell script),是一种为 shell 编写的脚本程序。
0.1 执行shell
方法1:作为可执行程序
保存为 test.sh,并 cd 到相应目录:
chmod +x ./test.sh #使脚本具有执行权限
./test.sh #执行脚本
注意,一定要写成 ./test.sh,而不是 test.sh
方法2:作为解释器参数
直接运行解释器,其参数就是 shell 脚本的文件名(该脚本文件可以无 "执行权限"。)
sh test.sh
1 shell变量
1.1 定义变量
定义变量时,变量名不加美元符号
以下语句将 /etc 下目录的文件名循环出来。
for file in `ls /etc`
或
for file in $(ls /etc)
1.2 使用变量
使用一个定义过的变量,只要在变量名前面加美元符号即可
花括号是可选的(加花括号是为了帮助解释器识别变量的边界。推荐给所有变量加上花括号,这是个好的编程习惯。),但是一定要加美元符号
1.3 设置只读变量(readonly)
1.4 删除变量(unset)
变量被删除后不能再次使用。
unset 命令不能删除只读变量。
2 shell 字符串
2.1 单引号
单引号里的任何字符都会原样输出,单引号字符串中的变量是无效的;
单引号字串中不能出现单独一个的单引号(对单引号使用转义符后也不行)
但单引号可成对出现,作为字符串拼接使用。
2.2 双引号
- 双引号里可以有变量(变量需要$b使用)
- 双引号里可以出现转义字符(用echo -e显示转义字符)
和单引号一样,双引号也能拼接字符
2.3 获取字符串长度
也可以用length
2.4 截取子字符串
2.4.1 按照下标截取
假设有变量 var=http://www.aaa.com/123.htm
echo ${var:0:5} | 0 表示左边第一个字符开始,5 表示字符的总个数。 结果是:http: |
echo ${var:7} | 7 表示左边第8个字符开始,一直到结束。 结果是 :www.aaa.com/123.htm |
echo ${var:0-7:3} | 0-7 表示右边算起第七个字符开始,3 表示字符的个数。 结果是:123 |
echo ${var:0-7}
| 从右边第七个字符开始,一直到结束。 结果是:123.htm |
注:(左边的第一个字符是用 0 表示,右边的第一个字符用 0-1 表示)
2.4.2 #截取
#、## 表示从左边开始删除。
一个 # 表示从左边删除到第一个指定的字符;
两个 # 表示从左边删除到最后一个指定的字符。
假设有变量 var=http://www.aaa.com/123.htm
echo ${var#*//} | 从左边开始删除第一个 // 号及左边的所有字符, 即删除 http:// 结果是 :www.aaa.com/123.htm |
echo ${var##*/} | 表示从左边开始删除最后(最右边)一个 / 号及左边的所有字符, 结果是 123.htm |
2.4.3 %截取
%、%% 表示从右边开始删除。
一个 % 表示从右边删除到第一个指定的字符;
两个 % 表示从右边删除到最后一个指定的字符。
假设有变量 var=http://www.aaa.com/123.htm
echo ${var%/*} | 从右边开始,删除第一个 / 号及右边的字符 结果是:http://www.aaa.com |
echo ${var%%/*} | 从右边开始,删除最后(最左边)一个 / 号及右边的字符 结果是:http: |
2.5 查找子字符串
注意,以上脚本中,`是反引号(键盘1左边那个),不是单引号
3 shell数组
3.1 定义数组
在 Shell 中,用括号来表示数组,数组元素用"空格"符号分割开。定义数组的一般形式为:
数组名=(值1 值2 ... 值n)
使用不连续的下标,如果接下来要读取没有赋值的下标位置的数组,不会报错,但也不会有什么返回。
3.2 读取数组
下标可以是变量(变量前面加不加$都可以)
3.3 获取数组所有元组
使用 @/* 符号可以获取数组中的所有元素
3.4 获取数组长度
获取数组长度的方式和获取字符串长度的方式相同
4 shell注释
4.1 单行注释
以 # 开头的行就是注释,会被解释器忽略。
通过每一行加一个 # 号设置多行注释
4.2 多行注释
5 shell传参
我们可以在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n。
n 代表一个数字,1 为执行脚本的第一个参数,2 为执行脚本的第二个参数,以此类推……
$# | 传递到脚本的参数个数 |
$* | 以一个单字符串显示所有向脚本传递的参数,以"$1 $2 … $n"的形式输出所有参数 |
$$ | 脚本当前的进程ID号 |
$@ | 与$*相同,但是使用时加引号,并在引号中返回每个参数。 如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。 |
5.1 *和@的区别
$* 与 $@ 区别:
- 相同点:都是引用所有参数。
- 不同点:只有在双引号中体现出来。假设在脚本运行时写了三个参数 1、2、3,,则 " * " 等价于 "1 2 3"(传递了一个参数),而 "@" 等价于 "1" "2" "3"(传递了三个参数)。
echo "-- \$* 演示 ---"
for i in "$*"; do
echo $i
done
echo "-- \$@ 演示 ---"
for i in "$@"; do
echo $i
done
6 shell基本运算符
注意事项:
1,表达式和运算符之间要有空格,例如 2+2 是不对的,必须写成 2 + 2,这与我们熟悉的大多数编程语言不一样。
2,完整的表达式要被 ` ` 包含,注意这个字符不是常用的单引号,在 Esc 键下边。
3,常用的 + - * / % = == != ,shell上都有
4,乘号(*)前边必须加反斜杠(\)才能实现乘法运算;(在 MAC 中 shell 的 expr 语法是:$((表达式)),此处表达式中的 "*" 不需要转义符号 "\" )
5,条件表达式要放在方括号之间,并且要有空格,例如: [$a==$b] 是错误的,必须写成 [ $a == $b ]。
6.1 shell关系运算符
-eq | 判断是否相等 (equal) |
-ne | 判断是否不相等 (not equal) |
-gt | 判断是否大于 (greater than) |
-lt | 判断是否小于 (less than) |
-ge | 判断是否大于等于 (greater equal) |
-le | 判断是否小于等于 (less equal) |
6.2 shell布尔运算符
! | 非 |
-o | 或运算(or) |
-a | 与运算(and) |
6.3 字符串运算符
= | 两个字符串是否相等 |
!= | 判断两个字符串是否不相等 |
-z | 字符串长度是否为0(为0返回true) |
-n | 字符串长度是否不为0(不为0返回true) |
6.4 shell逻辑运算符
&& | 逻辑的 AND |
|| | 逻辑的 OR |
6.5 文件测试运算符
-d file | 检测文件是否是目录,如果是,则返回 true。 | [ -d $file ] 返回 false。 |
-f file | 检测文件是否是普通文件,如果是,则返回 true。 | [ -f $file ] 返回 true。 |
-r file | 检测文件是否可读,如果是,则返回 true。 | [ -r $file ] 返回 true。 |
-w file | 检测文件是否可写,如果是,则返回 true。 | [ -w $file ] 返回 true。 |
-x file | 检测文件是否可执行,如果是,则返回 true。 | [ -x $file ] 返回 true。 |
-s file | 检测文件是否为空(文件大小是否大于0),不为空返回 true。 | [ -s $file ] 返回 true。 |
-e file | 检测文件(包括目录)是否存在,如果是,则返回 true。 | [ -e $file ] 返回 true。 |
7 shell echo 命令
7.1 显示普通字符
7.2 显示双引号
7.3 -e 开启转义
7.4 显示结果定向至某文件
7.5 显示命令执行结果
8 shell 流程控制
和一般的语言不一样,shell的流程控制不可为空,也就是说,如果else分支没有语句可以执行,那么就不要写这个else
要注意的是,和 C 语言不同,shell 语言中 0 代表 true,0 以外的值代表 false。
8.1 if-else
8.2 if-elif-else
8.3 for
8.4 while
几种自增的方法
let j++
let "n++"
let m+=1
a=$[$a+1]
8.5 until
一直循环,直到某一次条件为true
8.6 case
每个 case 分支用右圆括号开始,用两个分号 ;; 表示 break,即执行结束,跳出整个 case ... esac 语句。
取值将检测匹配的每一个模式。一旦模式匹配,则执行完匹配模式相应命令后不再继续其他模式。如果无一匹配模式,使用星号 * 捕获该值,再执行后面的命令。
8.7 跳出循环
shell中也有break和continue
9 shell 重定向
command > file | 将输出重定向到file |
command < file | 将输入重定向到file |
command >> file | 将输出以追加(append)的方式重定向到file |
n > file | 将文件描述符为n的文件重定向到file |
n >> file | 将文件描述符为n的文件以追加的方式重定向到file |
n >& m | 将输出文件m和n合并 |
9.1 文件描述符
0 | 标准输入 STDIN |
1 | 标准输出 STDOUT |
2 | 标准错误输出 STDERR |
9.2 举例
将 stdout 和 stderr 合并后重定向到 file
10 printf
printf 命令模仿 C 程序库(library)里的 printf() 程序
printf "%-10s %-8s %-4s\n" 姓名 性别 体重kg
printf "%-10s %-8s %-4.2f\n" 小赵 男 66.1234
printf "%-10s %-8s %-4.2f\n" 小钱 男 48.6543
printf "%-10s %-8s %-4.2f\n" 小孙 女 47.9876
%s %c %d %f 都是格式替代符
%s 输出一个字符串(string)
%d 整型输出(decimal)
%c 输出一个字符(char)
%f 输出浮点数。(float)
%-10s 指一个宽度为 10 个字符(- 表示左对齐,没有则表示右对齐),任何字符都会被显示在 10 个字符宽的字符内,如果不足则自动以空格填充,超过也会将内容全部显示出来。
%-4.2f 指格式化为小数,其中 .2 指保留2位小数。
format-string 单引号双引号效果一样。
如果format-string中只有一个,甚至没有引号都可以
格式只指定了一个参数,但多出的参数仍然会按照该格式输出,format-string 被重用
如果没有 arguments,那么 %s 用NULL代替,%d 用 0 代替
格式化浮点数默认支持小数点后面六位,多出来的四舍五入
10.1 printf 转义序列
大体上和C是一样的
\b | 后退 |
\c | 抑制(不显示)输出结果中任何结尾的换行字符 |
\f | 换页(formfeed) |
\n | 换行 |
\t | 水平制表符 |
\v | 垂直制表符 |
\\ | 一个字面上的反斜杠字符 |
\ddd | 表示1到3位数八进制值的字符。仅在格式字符串中有效 |
\0ddd | 表示1到3位的八进制值字符,开头有一个0 |
11 shell函数
linux shell 可以用户定义函数,然后在shell脚本中可以随便调用。
11.1 函数定义
shell中函数的定义格式如下:
- 1、可以带function fun() 定义,也可以直接fun() 定义,不带任何参数。
- 2、参数返回,可以显示加:return 返回,如果不加,将以最后一条命令运行结果,作为返回值。 return后跟数值n(0-255)
下面定义一个带有return语句的函数:
funWithReturn(){
echo "这个函数会对输入的两个数字进行相加运算..."
echo "输入第一个数字: "
read aNum
echo "输入第二个数字: "
read anotherNum
echo "两个数字分别为 $aNum 和 $anotherNum !"
return $(($aNum+$anotherNum))
}
那么我们怎么得到函数返回的值呢?使用$? 即可
$? 仅对其上一条指令负责,一旦函数返回后其返回值没有立即保存入参数,那么其返回值将不再能通过 $? 获得。
11.2 函数参数
在Shell中,调用函数时可以向其传递参数。
在函数体内部,通过 $n 的形式来获取参数的值,例如,$1表示第一个参数,$2表示第二个参数...
funWithParam(){
echo "第一个参数为 $1 !"
echo "第二个参数为 $2 !"
echo "第十个参数为 $10 !"
echo "第十个参数为 ${10} !"
echo "第十一个参数为 ${11} !"
echo "参数总数有 $# 个!"
echo "作为一个字符串输出所有参数 $* !"
}
注意,$10 不能获取第十个参数,获取第十个参数需要${10}。当n>=10时,需要使用${n}来获取参数。
还有几个特殊的参数,和第五节shell传参是一样的
$# | 传递到脚本的参数个数 |
$* | 以一个单字符串显示所有向脚本传递的参数,以"$1 $2 … $n"的形式输出所有参数 |
$$ | 脚本当前的进程ID号 |
$@ | 与$*相同,但是使用时加引号,并在引号中返回每个参数。 如"$@"用「"」括起来的情况、以"$1" "$2" … "$n" 的形式输出所有参数。 |