Shell 教程
Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁。Shell 既是一种命令语言,又是一种程序设计语言。
Shell 是指一种应用程序,这个应用程序提供了一个界面,用户通过这个界面访问操作系统内核的服务。
Ken Thompson 的 sh 是第一种 Unix Shell,Windows Explorer 是一个典型的图形界面 Shell。
Shell 脚本
Shell 脚本(shell script),是一种为 shell 编写的脚本程序。
业界所说的 shell 通常都是指 shell 脚本,但读者朋友要知道,shell 和 shell script 是两个不同的概念。
由于习惯的原因,简洁起见,本文出现的 “shell编程” 都是指 shell 脚本编程,不是指开发 shell 自身。
Shell 环境
Shell 编程跟 java、php 编程一样,只要有一个能编写代码的文本编辑器和一个能解释执行的脚本解释器就可以了。
Linux 的 Shell 种类众多,常见的有:
- Bourne Shell(/usr/bin/sh或/bin/sh)
- Bourne Again Shell(/bin/bash)
- C Shell(/usr/bin/csh)
- K Shell(/usr/bin/ksh)
- Shell for Root(/sbin/sh)
- ……
本教程关注的是 Bash,也就是 Bourne Again Shell,由于易用和免费,Bash 在日常工作中被广泛使用。同时,Bash 也是大多数Linux 系统默认的 Shell。
在一般情况下,人们并不区分 Bourne Shell 和 Bourne Again Shell,所以,像 #!/bin/sh,它同样也可以改为 #!/bin/bash。
#! 告诉系统其后路径所指定的程序即是解释此脚本文件的 Shell 程序。
第一个shell脚本
打开文本编辑器(可以使用 vi/vim 命令来创建文件),新建一个文件 test.sh,扩展名为 sh(sh代表shell),扩展名并不影响脚本执行,见名知意就好,如果你用 php 写 shell 脚本,扩展名就用 php 好了。
输入一些代码,第一行一般是这样:
实例
#!/bin/bash echo "Hello World !"
#! 是一个约定的标记,它告诉系统这个脚本需要什么解释器来执行,即使用哪一种 Shell。
echo 命令用于向窗口输出文本。
运行 Shell 脚本有两种方法:
1、作为可执行程序
将上面的代码保存为 test.sh,并 cd 到相应目录:
chmod +x ./test.sh #使脚本具有执行权限 ./test.sh #执行脚本
注意,一定要写成 ./test.sh,而不是 test.sh,运行其它二进制的程序也一样,直接写 test.sh,linux 系统会去 PATH 里寻找有没有叫 test.sh 的,而只有 /bin, /sbin, /usr/bin,/usr/sbin 等在 PATH 里,你的当前目录通常不在 PATH 里,所以写成 test.sh 是会找不到命令的,要用 ./test.sh 告诉系统说,就在当前目录找。
2、作为解释器参数
这种运行方式是,直接运行解释器,其参数就是 shell 脚本的文件名,如:
/bin/sh test.sh /bin/php test.php
这种方式运行的脚本,不需要在第一行指定解释器信息,写了也没用。
第1章 shell基础
1.1 什么是shell
Shell是一个命令解释器,它在操作系统的最外层,负责直接与用户对话,把用户的输入解释给操作系统,并处理各种各样的操作系统的输出结果,输出屏幕返回给用户。
1.1.1 shell对话方式
交互的方式:从键盘输入命令,通过/bin/bash的解析,可以立即得到Shell的回应,一问一答的方式
非交互式:shell脚本
1.2 为什么使用shell编程
作为一个合格的运维人员必须掌握一种或一种以上的脚本语言,shell编程则是实现Linux/UNIX系统管理及自动化运维所必备的重要工具,可以把繁琐重复的命令写到shell脚本中执行,节约时间,有效的提高运维人员的工作效率,减少不必要的重复工作时间。
1.3 系统中的shell
linux系统默认shell是bash
[root@zeq ~]# cat /etc/shells /bin/sh /bin/bash /sbin/nologin /bin/dash /bin/tcsh /bin/csh
第2章 变量
2.1 什么是变量
x+y=20 x=10 y=? 未知数(变量)
一个未知数,随时可以变化的量叫变量
2.2 变量的分类
2.2.1 普通变量(局部变量)
只能在当前环境下使用,可以通过export命令临时把普通变量变为环境变量使用
[root@zeq ~]# ip=10.0.0.201 给变量赋值(把数据存放到变量中) [root@zeq ~]# echo $ip 10.0.0.201
2.2.2 环境变量(全局变量)
1.大写
2.系统定义的
3.在大部分地方可以使用
2.2.3 特殊变量
$1 $2 $数字 $后数字是几代表shell脚本第几个参数
$# shell脚本中参数的个数
判断脚本的参数个数
$? 上一个命令的执行结果(返回值)
0 执行正确
非0 执行失败
$0 脚本文件名
第3章 shell脚本的书写规范
3.1.1 脚本存放位置
为了防止脚本乱放,统一存放在/server/scripts/中
创建目录
[root@zeq ~]# mkdir -p /server/scripts/ [root@zeq ~]# cd /server/scripts/
3.1.2 脚本编辑使用vim
3.1.3 选择解释器
在执行bash脚本的时候,内核会根据”#!”后的解释器来确定该用那个程序解释这个脚本中的内容。
[root@zeq ~]# vim /server/scripts/cal.sh #!/bin/bash
3.1.4 文件名书写
文件名称一定要有意义,方便看出是干嘛用的脚本,并且以.sh结尾
3.1.5 书写脚本的规范和习惯
1、 放在统一目录下,方便查找
2、 书写脚本要用vim编辑,
批量删除
批量增加
1.进入批量编辑模式(可视块)esc下ctrl+v
2.选择 批量增加的范围
3.按 shift + i 进行修改
4.按esc 退出等等
3、 脚本文件名称以.sh结束
4、 脚本开头一定要指定解释器
5、 脚本中#代表注释,#后的内容不会执行,不用的命令等可以用#注释掉,脚本中尽量不要出现中文注释以免出现因字符集不同产生乱码
6、 代码符号书写规范
1.成对的符号一定要都写出来再添加内容,避免遗忘漏写;如 “” ” []等
2.流程控制语句一次书写完,再添加内容;(if 条件 ; then 内容;fi)
3.书写的代码符号都是英文输入法格式
4.通过缩进让代码易读
第4章 shell练习
书写一个计算器脚本
4.1 数字计算方法
[root@zeq ~]# awk 'BEGIN{print 1/2}' 0.5
4.1.1 命令行中的变量 放在awk中使用
awk -v变量=赋值 变量名称自己定义
[root@zeq ~]# awk -vnum1=10 -vnum2=20 'BEGIN{print num1/num2 }' 这里变量为num1和num2 0.5
4.1.2 书写脚本计算10与20的加减乘除
[root@zeq]# vim cal.sh #!/bin/bash n1=10 n2=20 awk -vnum1=$n1 -vnum2=$n2 'BEGIN{print num1+num2 }' awk -vnum1=$n1 -vnum2=$n2 'BEGIN{print num1-num2 }' awk -vnum1=$n1 -vnum2=$n2 'BEGIN{print num1*num2 }' awk -vnum1=$n1 -vnum2=$n2 'BEGIN{print num1/num2 }'
执行脚本
[root@zeq /server/scripts]# sh cal.sh 30 -10 200 0.5
4.1.3 定义特殊变量 通过命令行传递参数方式进行计算
[root@zeq /server/scripts]# vim cal.sh #!/bin/bash n1=$1 第一个参数 n2=$2 第二个参数 awk -vnum1=$n1 -vnum2=$n2 'BEGIN{print num1+num2 }' awk -vnum1=$n1 -vnum2=$n2 'BEGIN{print num1-num2 }' awk -vnum1=$n1 -vnum2=$n2 'BEGIN{print num1*num2 }' awk -vnum1=$n1 -vnum2=$n2 'BEGIN{print num1/num2 }'
执行脚本
[root@zeq /server/scripts]# sh cal.sh 10 20 后面要跟上两个参数才能执行成功,参数之前加空格 30 -10 200 0.5
4.2 通过read 交互式
read交互式赋予变量内容
read -p “提示信息:” 变量名字
read -p “提示信息:” p
执行之后会把输入的信息存放在变量中
[root@zeq /server/scripts]# read -p "input num1:" n1 input num1:zeq [root@zeq /server/scripts]# echo $n1 zeq
4.2.1 通过read命令实现 n1 n2赋值 进行计算
[root@zeq /server/scripts]# vim cal.read.sh #!/bin/bash read -p "input num1,num2:" n1 n2 一条命令直接定义两个变量 awk -vnum1=$n1 -vnum2=$n2 'BEGIN{print num1+num2 }' awk -vnum1=$n1 -vnum2=$n2 'BEGIN{print num1-num2 }' awk -vnum1=$n1 -vnum2=$n2 'BEGIN{print num1*num2 }' awk -vnum1=$n1 -vnum2=$n2 'BEGIN{print num1/num2 }'
执行脚本
[root@zeq /server/scripts]# sh cal.read.sh input num1,num2:10 20 随便输入两个数值,中间要有空格 30 -10 200 0.5
4.3 条件表达式 if
4.3.1 判断目录、文件是否存在
[ -d /data ]
[ -f /data ]
注意格式:[空格-f /data空格] []里面两端必须有空格,中间写内容
[root@zeq /server/scripts]# [ -d /data ] [root@zeq /server/scripts]# echo $? $?特殊变量,0代表执行正确,非0执行失败 0 [root@zeq /server/scripts]# [ -d /data123 ] [root@zeq /server/scripts]# echo $? 1
4.3.2 比大小
-eq equal == -ne not equal != -gt great than > -ge great equal >= -lt less than < -le less equal <=
4.3.3 比大小举例
[root@zeq /server/scripts]# [ 10 -eq 10 ] [root@zeq /server/scripts]# echo $? 0 [root@zeq /server/scripts]# [ 10 -gt 10 ] [root@zeq /server/scripts]# echo $? 1 [root@zeq /server/scripts]# [ 10 -ge 10 ] [root@zeq /server/scripts]# echo $? 0
4.3.4 if单分支格式脚本
格式: if [ 条件 ];then
命令
fi
1、判断脚本的参数个数,如果不是2则提示请输入两个数字
[root@zeq /server/scripts]# cat pan.sh #!/bin/bash if [ $# -ne 2 ];then echo "输入两个数字" fi
2、 给计算器(参数传递)增加一个条件
判断脚本的参数个数,
如果不是2则
提示请输入两个数字
[root@zeq /server/scripts]# cat cal.sh #!/bin/bash n1=$1 n2=$2 if [ $# -ne 2 ];then echo "USAGE: $0 num1 num2" $0文件名 exit exit 退出的意思 fi awk -vnum1=$n1 -vnum2=$n2 'BEGIN{print num1+num2 }' awk -vnum1=$n1 -vnum2=$n2 'BEGIN{print num1-num2 }' awk -vnum1=$n1 -vnum2=$n2 'BEGIN{print num1*num2 }' awk -vnum1=$n1 -vnum2=$n2 'BEGIN{print num1/num2 }'
3、执行脚本
[root@zeq /server/scripts]# sh cal.sh USAGE: cal.sh num1 num2 [root@zeq /server/scripts]# sh cal.sh 120 20 140 100 2400 6
4.3.5 if双分支格式脚本
格式: if [ 条件 ];then
命令
else
命令
fi
1、comp.sh输入两个数字:
1.如果n1大于n2
输出 n1 > n2
2.如果n1不大于n2
输出 n1 <= n2
[root@zeq /server/scripts]# cat comp.sh #!/bin/bash n1=$1 n2=$2 if [ $n1 -gt $n2 ];then echo "$n1 > $n2" else echo "$n1 <= $n2" fi
2、执行脚本
[root@zeq /server/scripts]# sh comp.sh 10 20 10 <= 20 [root@zeq /server/scripts]# sh comp.sh 10 10 10 <= 10 [root@zeq /server/scripts]# sh comp.sh 100 10 100 > 10
本人学习环境Ubuntu12.04 server虚拟机。
shell种类
目前流行的Shell有ash, bash, ksh, csh, zsh等,你可以用下面的命令来查看你自己的Shell类型:
# echo $SHELL
$SHELL是一个环境变量,它记录用户所使用的Shell类型。你可以用命令:
# Shell-name
来转换到别的Shell,这里Shell-name是你想要尝试使用的Shell的名称,如ash等。这个命令为用户又启动了一个Shell,这个Shell在最初登录的那个Shell之后,称为下级的Shell或子Shell。
使用命令:
# exit
可以退出这个子Shell。
使用不同的Shell的原因在于它们各自都有自己的特点,下面做一个简单的介绍:
1.ash
ash Shell是由Kenneth Almquist编写的,是Linux中占用系统资源最少的一个小Shell,它只包含24个内部命令,因而使用起来很不方便。
2.bash
bash是Linux系统默认使用的Shell,它由Brian Fox和Chet Ramey共同完成,是Bourne Again Shell的缩写,内部命令一共有40个。Linux使用它作为默认的Shell是因为它有以下的特色:
(1)可以使用类似DOS下面的doskey的功能,用上下方向键查阅和快速输入并修改命令。
(2)自动通过查找匹配的方式,给出以某字串开头的命令。
(3)包含了自身的帮助功能,你只要在提示符下面键入help就可以得到相关的帮助。
3.ksh
ksh是Korn Shell的缩写,由Eric Gisin编写,共有42条内部命令。该Shell最大的优点是几乎和商业发行版的ksh完全相容,这样就可以在不用花钱购买商业版本的情况下尝试商业版本的性能了。
4.csh
csh是Linux比较大的内核,它由以William Joy为代表的共计47位作者编成,共有52个内部命令。该Shell其实是指向/bin/tcsh这样的一个Shell,也就是说,csh其实就是tcsh。
5.zch
zch是Linux最大的Shell之一,由Paul Falstad完成,共有84个内部命令。如果只是一般的用途,是没有必要安装这样的Shell的。
Ubuntu 默认为bash。
Hello world
1、新建文件
vi helloworld.sh
1 #!/bin/bash //开头必备 2 3 #print hello world in the console window 4 5 a="hello world" //=号两边不能有空格 6 7 echo $a
2、赋予权限
chmod +x filename.sh
3、执行
./helloworld.sh
详细学习
这部分,我参考的博文就很好,这里引用过来,方便查看。
下面我们来看一个更复杂的例子,结合这个例子,我们来讲述Shell Script的语法。 #!/bin/bash # we have less than 3 arguments. Print the help text: if [ $# -lt 3 ]; then cat<<HELP ren -- renames a number of files using sed regular expressions USAGE: ren 'regexp' 'replacement' files EXAMPLE: rename all *.HTM files in *.html: ren 'HTM$' 'html' *.HTM HELP exit 0 fi OLD="$1" NEW="$2" # The shift command removes one argument from the list of # command line arguments. shift shift # $* contains now all the files: for file in $*; do if [ -f "$file" ]; then newfile=`echo "$file" | sed "s/${OLD}/${NEW}/g"` if [ -f "$newfile" ]; then echo "ERROR: $newfile exists already" else echo "renaming $file to $newfile " mv "$file" "$newfile" fi fi done 我们从头来看,前面两行上一个例子中已经解释过了,从第三行开始,有新的内容。if语句和其他编程语言相似,都是流程控制语句。它的语法是: if …; then … elif …; then … else … fi 与其他语言不同,Shell Script中if语句的条件部分要以分号来分隔。第三行中的[]表示条件测试,常用的条件测试有下面几种: [ -f "$file" ] 判断$file是否是一个文件 [ $a -lt 3 ] 判断$a的值是否小于3,同样-gt和-le分别表示大于或小于等于 [ -x "$file" ] 判断$file是否存在且有可执行权限,同样-r测试文件可读性 [ -n "$a" ] 判断变量$a是否有值,测试空串用-z [ "$a" = "$b" ] 判断$a和$b的取值是否相等 [ cond1 -a cond2 ] 判断cond1和cond2是否同时成立,-o表示cond1和cond2有一成立 要注意条件测试部分中的空格。在方括号的两侧都有空格,在-f、-lt、=等符号两侧同样也有空格。如果没有这些空格,Shell解释脚本的时候就会出错。 $#表示包括$0在内的命令行参数的个数。在Shell中,脚本名称本身是$0,剩下的依次是$0、$1、$2…、${10}、${11},等等。$*表示整个参数列表,不包括$0,也就是说不包括文件名的参数列表。 现在我们明白第三行的含义是如果脚本文件的参数少于三个,则执行if和fi语句之间 的内容。然后,从第四行到第十一行之间的内容在Shell Script编程中被称为Here文档,Here文档用于将多行文本传递给某一命令。Here文档的格式是以<<开始,后跟一个字符串,在 Here文档结束的时候,这个字符串同样也要出现,表示文档结束。在本例中,Here文档被输出给cat命令,也即将文档内容打印在屏幕上,起到显示帮助 信息的作用。 第十二行的exit是Linux的命令,表示退出当前进程。在Shell脚本中可以使用所有的Linux命令,利用上面的cat和exit,从一方面来说,熟练使用Linux命令也可以大大减少Shell脚本的长度。 十四、十五两句是赋值语句,分别将第一和第二参数赋值给变量OLD和NEW。紧接下来的两句是注释,注释下面的两条shift的作用是将参数列表中的第一个和第二个参数删除,后面的参数依次变为新的第一和第二参数,注意参数列表原本也不包括$0。 然后,自二十一行到三十一行是一个循环语句。Shell Script中的循环有下面几种格式: while [ cond1 ] && { || } [ cond2 ] …; do … done for var in …; do … done for (( cond1; cond2; cond3 )) do … done until [ cond1 ] && { || } [ cond2 ] …; do … done 在上面这些循环中,也可以使用类似C语言中的break和continue语句中断 当前的循环操作。第二十一行的循环是将参数列表中的参数一个一个地放入变量file中。然后进入循环,判断file是否为一个文件,如果是文件的话,则用 sed命令搜索和生成新的文件名。sed基本上可以看成一个查找替换程序,从标准输入,例如管道读入文本,并将结果输出到标准输出,sed使用正则表达式 进行搜索。在第二十三行中,backtick(`)的作用是取出两个backtick之间的命令输出结果,在这里,也就是将结果取出赋给变量 newfile。此后,判断newfile是否已经存在,否则就把file改成newfile。这样我们就明白这个脚本的作用了,Shell Script编写的其他脚本与此相似,只不过是语法和用法稍有不同而已。