Shell 脚本编程
1. 什么是 shell ?
Computers understand the language of zeros and ones known as binary language. In the early days of computing, instructions were provided using binary language, which is difficult for all of us to read and write. Therefore, in an operating system there is a special program called the shell. The shell accepts human readable commands and translates them into something the kernel can read and process.
shell 就是将人类可读的指令转换成计算机内核能够识别并执行的程序。
常见的 shell 有:
- Bourne Shell(sh)
- Bourne Again shell(bash)
- C Shell(csh)
- TENEX C Shell(tcsh)
- Korn shell(ksh)
- Z Shell(zsh)
- Friendly Interactive Shell(fish)
bash 是目前使用最多的 shell 。
shell 脚本 就是将完成一个任务的所有的命令按照执行的先后顺序,自上而下写入到一个文本文件中,然后给予执行权限。
比如:这是一个安装 ngixn 的脚本:
0 #!/bin/bash
1 #install gcc
2 yum -y install wget gcc pcre-devel zlib-devel
3 #get nginx
4 wget http://nginx.org/download/nginx-1.16.0.tar.gz
5
6 tar xf nginx-1.16.0.tar.gz
7
8 cd nginx-1.16.0
9
10 ./configure --prefix=/usr/local/nginx
11 make
12 make install
给脚本赋予权限 chmod 700 ngnix_installation_script.sh
或者 sh nginx_installation_script.sh
, 就可以运行了.
2. shell 脚本基础
2.1 注释和命名
- shell 中使用
#
进行注释 - 脚本的第一行通常是指定解释器,即这个脚本必须通过什么解释器执行。这一行以
#!
字符开头,这个字符称为 Shebang,所以这一行就叫做 Shebang 行。 - shell 脚本文件的命名和其他编程语言的命名类似,数字不能开头,
2.2 运行一个脚本
脚本运行需要执行权限,当我们给一个文件赋予执行权限后,该脚本就可以运行。
chmod u+x script_fileName
- 直接使用 bash 进行运行
bash script_fileName
2.3 shell 中的特殊符号,(会被特殊对待)
~
家目录!
执行历史命令,!!
表示执行上一条命令$
去变量符号&
后台执行*
shell 中的通配符号, 匹配所有?
shell 中的通配符号, 匹配除回车外的一个字符;
多条命令之间的分割符号|
管道符号\
转义符号- ` 反引号, 命令中执行命令
''
单引号, 脚本中字符串需要用单引号括起来,但是不会解释变量""
双引号, 用于包裹字符串
2.4 shell 中的重定向
>
重定向输入 覆盖原始的数据>>
从定向追加输入, 在原来的文件中追加数据<
重定向输出wc -l < /etc/passwd
统计数据流<<
重定向追加输出fdisk /dev/sdb <
格式化硬盘,重新缓存。
#!/bin/bash fdisk /dev/sdb << EOF n p 3 +534M w EOF
2.5 shell 中的数学运算
- expr 只能整数运算, 格式比较古板 需要有空格
expr 1 + 1
- bc 使用 bc 计算器处理浮点运算,
scale=2
代表小数点保留两位echo "scale=2;3+100"|bc
- 双小圆括号进行运算 shell 中
(())
可以用来做数学运算echo $(( 100**3 ))
2.6 退出脚本
exit NUM 退出脚本, 释放系统资源 (NUM 代表一个整数) 代表脚本的返回值
man exit 查看详细
3. 输出和输入
3.1 输出
3.1.1 echo
echo
命令的作用是在屏幕输出一行文本,可以将该命令的参数原样输出。
-n
: 在文本末尾不添加换行符号-e
: 解释 引号中的特殊字符 (双引号和单引号)-b
: 删除一个符号倒计时脚本:
#!/bin/bash for time in `seq 9 -1 0`;do echo -ne "\b$time" sleep 1 done
3.2 输入
3.2.1 脚本的传参
$1
: 在执行 Shell 脚本时,向脚本传递参数,脚本内获取参数的格式为:$n
。n
代表一个数字,,其中$0
为执行的文件名(包含文件路径),$1
为执行脚本的第一个参数,$2
为执行脚本的第二个参数,以此类推……$#
: 传递到脚本的参数个数$*
: 以一个单字符串显示所有向脚本传递的参数。 如$*
用「"」括起来的情况、以$1
$2
…$n
的形式输出所有参数。$$
: 脚本运行的当前进程 ID 号$!
: 后台运行的最后一个进程的 ID 号$@
: 与$*
相同,但是使用时加引号,并在引号中返回每个参数。 如"$@"
用「"」
括起来的情况、以"$1""$2" … "$n"
的形式输出所有参数。$-
: 显示 Shell 使用的当前选项,与 set 命令 功能相同。$?
: 显示最后命令的退出状态。0 表示没有错误,其他任何值表明有错误。
3.2.2 Read
命令
默认接受键盘的输入,回车符代表输入结束
-p
: 打印信息-t
: 限定时间-s
: 不回显-n
: 输入字符个数
#!/bin/bash
clear
echo -n -e "type something"
read var
echo "you typed:" $var
4. shell 变量
4.1 变量的操作
- 定义变量格式:
变量名 = 值
(不能有空号) - 使用
$
进行变量的读取 - 使用
unset 变量名
取消变量
4.2 分类
- 本地变量:用户私有变量,只有 本用户可以使用,保存在家目录下的
.bash_profile
、.bashrc
文件中 - 全局变量:所有用户都可以使用,保存在
/etc/profile
、/etc/bashrc
文件中。使用export 变量名 = 变量值
进行全局变量的定义 - 用户自定义变量:用户自定义,比如脚本中的变量,终端关闭或者关机,都会丢失,
6. shell 数组
6.1 基本数组
6.1.1 数组语法
- 定义:
数组名称 =(元素 1 元素 2 元素 3 ...)
- 数组的读出
${数组名称}[index]
6.1.2 数组的赋值
方法一: 一次赋一个值
array0[0]='tom'
方法二: 一次赋予多个值
array2=(tom jack alice)
array3=(cat /etc/passwd) #希望是将该文件中的每一个行作为一个元素赋值给数组 array3
array4=(ls /var/ftp/Shell/for*)
array5=(tom jack alice “bash shell”)
6.1.3 访问数组元素
echo ${array1[0]} 访问数组中的第一个元素
echo ${array1[@]} 访问数组中所有元素 等同于 echo ${array1[*]}
echo ${#array1[@]} 统计数组元素的个数
echo ${!array2[@]} 获取数组元素的索引
echo ${array1[@]:1} 从数组下标 1 开始
echo ${array1[@]:1:2} 从数组下标 1 开始,访问两个元素
6.2 联合数组
关联数组可以允许用户自定义数组的索引,这样使用起来更加方便、高效。
需要先申明该数组为关联数组
#!/bin/bash
declare -A a_array
a_array=([name]='suzl' [age]='25')
echo ${a_array[name]}
访问数组元素:
echo ${ass_array2[index2]} 访问数组中的第二个元数
echo ${ass_array2[@]} 访问数组中所有元数 等同于 echo ${array1[*]}
echo ${#ass_array2[@]} 获得数组元数的个数
echo ${!ass_array2[@]} 获得数组元数的索引
7. 流程控制语句
7.0 shell 中的比较运算
7.0.1 数学运算
运算符解释
-eq
等于-gt
大于-lt
小于-ge
大于或等于-le
小于或等于-ne
不等于
7.0.2 字符串比较
运算符解释,注意字符串一定别忘了使用引号引起来
==
等于!=
不等于-n
检查字符串长度是否大于 0-z
检查字符串长度是否为 0
7.0.3 文件的检查和比较
-d
是否存在且为目录-e
检查文件是否存在-f
检查文件是否存在且为文件-s
检查文件是否存在且可读-w
检查文件是否存在且不为空-x
检查文件是否存在且可写-O
检查文件是否存在且可执行-G
检查文件是否存在并且被当前用户拥有file1 -nt file2
检查 file1 是否比 file2 新file1 -ot file2
检查 file1 是否比 file2 旧
7.1 if 条件要加 []
7.1.1if
语法
if [condition]
then
commands
fi
7.1.2 if-else
if [condition]
then
commands1
else
commands2
fi
7.1.3 if-else-elseif
if [condition 1]
then
commands1
elif [condition 2]
then
commands2
.......
else
commandsX
fi
7.1.4 if
的高级用法
- 条件符号使用双圆括号
(())
,可以在条件中植入数学表达式 - 使用双方括号
[[]]
, 可以在条件中 使用通配符
#!/bin/bash
if ((100*3+10>500 ));then
echo ">"
else
echo "<"
fi
for str in java javascript js
do
if [["$str" == j*]];then
echo "$str"
fi
done
7.2 for
7.2.1 for 语法
语法 1: 有限变量
for var in v1 v2 v3.. do command done
语法 2: C 语言写法
for ((变量; 条件; 变化)) do command done
语法 3: 无限循环
for ((;;)) do command done
7.2.1 循环控制
continue
跳过循环中的某次循环continue
跳过循环中的某次循环break
跳出循环继续执行后续代码, 可以使用break N
循环退出, 循环从里往外排序为1 - N
#!/bin/bash
for ((i=9;i>0;i--))
do
if [$i -eq 5]
then
continue
else
echo -n -e "\b$i==="
sleep 1
fi
done
echo -e
#!/bin/bash
for ((i=1;i<100;i++))
do
echo "ha"
for((;;))
do
echo "the inner loop"
break 2
done
done
打印:
ha
the inner loop
7.3 while
7.3.1 语法格式: 条件可以是 5 种运算中的任意一种
数学, 字符串比较, 文件类型, 逻辑运算, 赋值运算
while [condition]
do
command
done
7.4 until
while
是条件为真开始时循环, until
是条件为假开始循环.
7.5 case (多条件执行语句)
语法 (比较奇怪):
case var in
condition1)
command1
;;
condition1)
command2
;;
...
esac
注意 3.2.1 中特殊的变量
8. shell 函数
8.1 函数语法
# 方式 1
func_name (){
command
return N
}
# 方式 2
function func_name{
command
return N
}
8.2 调用函数
直接使用函数名字, 不加括号: func_name
9. 正则表达式
9.1 特殊字符
9.1.1 定位字符: 锚定字符
^
锚定开头^a
以 a 开头, 默认锚定一个字符$
锚定结尾a$
以 a 结尾, 默认锚定一个字符^$
两个字符在一起表示精准匹配grep
默认不支持正则表达式, 需要加上-e
参数, 或者使用egrep
其他特定符号的意思
9.1.2 匹配符: 匹配字符串
.
除了回车符号任意的字符(|)
字符串分组^(a|b)c$
a 或者 b 开头以 c 结尾的串[]
定义字符类, 匹配括号中的一个字符[^]
表示否定括号中出现字符类中的字符, 取反\
转义字符|
或符号
9.1.3 限定符号 : 对前面的字符或者字符串做限定说明
*
某个字符之后加星号表示该字符不出现或出现多次 (0 次或者多次 )?
与星号相似,但略有变化,表示该字符出现一次或不出现 (0 次或者 1 次)+
与星号相似,表示其前面字符出现 一次或多次 , 但必须出现一次{n,m}
某个字符之后出现,表示该字符 最少n
次, 最多m
次{m}
正好出现了m
次
9.1.4 POSIX 特殊字符
[:alnum:]
匹配任意字母字符 0-9 a-z A-Z[:alpha:]
匹配任意字母,大写或小写[:digit:]
数字 0-9[:graph:]
非空字符 ( 非空格控制字符)[:lower:]
小写字符 a-z[:upper:]
大写字符 A-Z[:cntrl:]
控制字符[:print:]
非空字符 ( 包括空格)[:punct:]
标点符号[:blank:]
空格和 TAB 字符[:xdigit:]
16 进制数字[:space:]
所有空白字符 ( 新行、空格、制表符)
10. shell 文件操作
非交互式文件操作, vim 和 nano 是交互式文件操作.
10.1 sed (stream editor)
10.2 awk(pattern-directed scanning and processing language)
参考链接
- 鸟哥的 Linux 私房菜
- 路飞学城 shell 教程
- The Linux Command Line