1、描述shell程序的运行原理(可附带必要的图形说明);
shell是用户和Linux操作系统之间的接口。Linux中有多种shell,其中缺省使用的是Bash。
Linux系统的shell作为操作系统的外壳,为用户提供使用操作系统的接口。它是命令语言、命令解释程序及程序设计语言的统称。
shell是用户和Linux内核之间的接口程序,如果把Linux内核想象成一个球体的中心,shell就是围绕内核的外层。当从shell或其他程序向Linux传递命令时,内核会做出相应的反应。
shell是一个命令语言解释器,它拥有自己内建的shell命令集,shell也能被系统中其他应用程序所调用。用户在提示符下输入的命令都由shell先解释然后传给Linux核心。
有一些命令,比如改变工作目录命令cd,是包含在shell内部的。还有一些命令,例如拷贝命令cp和移动命令rm,是存在于文件系统中某个目录下的单独的程序。对用户而言,不必关心一个命令是建立在shell内部还是一个单独的程序。
shell首先检查命令是否是内部命令,若不是再检查是否是一个应用程序(这里的应用程序可以是Linux本身的实用程序,如ls和rm,也可以是购买的商业程序,如xv,或者是自由软件,如emacs)。然后shell在搜索路径里寻找这些应用程序(搜索路径就是一个能找到可执行程序的目录列表)。如果键入的命令不是一个内部命令并且在路径里没有找到这个可执行文件,将会显示一条错误信息。如果能够成功找到命令,该内部命令或应用程序将被分解为系统调用并传给Linux内核。
shell的另一个重要特性是它自身就是一个解释型的程序设计语言,shell程序设计语言支持绝大多数在高级语言中能见到的程序元素,如函数、变量、数组和程序控制结构。shell编程语言简单易学,任何在提示符中能键入的命令都能放到一个可执行的shell程序中。
当普通用户成功登录,系统将执行一个称为shell的程序。正是shell进程提供了命令行提示符。作为默认值(TurboLinux系统默认的shell是BASH),对普通用户用“$”作提示符,对超级用户(root)用“#”作提示符。
一旦出现了shell提示符,就可以键入命令名称及命令所需要的参数。shell将执行这些命令。如果一条命令花费了很长的时间来运行,或者在屏幕上产生了大量的输出,可以从键盘上按ctrl+c发出中断信号来中断它(在正常结束之前,中止它的执行)。
2 总结shell编程中所涉及到的所有知识点(如:变量、语法、命令状态等等等,要带图的哟);
变量:变量事实上是一块命名的内存空间,可用于存储数据,且空间可以按需改变。
使用变量的通常步骤为:
1.声明,指定变量的类型。声明的同时,通常会给其一个初始值,这个过程叫做变量的初始化
2.赋值。变量的赋值用 = 表示,例如: A=10,
shell中的变量赋值:
变量名=值
★注意:变量在赋值时不能使用$;
变量名只能包含字母、数字和下划线,而且不能以数字开头;
变量名区别大小写;
bash变量种类:
本地变量:作用范围是当前shell进程
定义变量: [set]Var_Name="Value"
引用变量: ${Var_Name}
撤销变量: unset Var_Name
环境变量:作用范围是当前shell进程及其子进程
直接生成变量为环境变量:
export Var_Name="Value"
先定义本地变量,再使用export命令导出为环境变量
Var_Name="Value"
export Var_Name
示例:分别演示两种生成环境变量的方法
局部变量:某个函数执行过程,仅对局部代码生效
local Var_Name="Value"
位置参数变量:在脚本中引用传递给脚本的参数,在函数中引用传递给函数的参数
$1, $2, $3...$n
./script-name.sh 2 8
$0: 表示当前执行的进程名,script 本身的名字,或者在正则表达式中表示整行输出
$1: 传递给该shell脚本的第一个参数
$2: 传递给该shell脚本的第二个参数
$#: 位置参数的个数
$@: 引用所有的位置参数,将所有的位置参数分别显示
$*: 将所有的位置参数当做一个整体的字符串来显示
特殊变量:
$?: 上一条命令的执行状态;
状态用数字来表示:0-255;
0: 成功
1-255: 失败 (1、2、127 是系统预留的)
$!: 在后台运行的最后的工作的PID(进程ID).
$$: 脚本自身的进程ID.这个变量经常用来构造一个"unique"的临时文件名.
示例:
变量类型:
限定了数据的存储格式和数据的表示范围主要有
数值型:
整数、浮点数
文本型:
字符
bash中如何引用变量:
'' 强引用,变量替换不会进行
"" 弱引用,能够执行变量替换
`` 命令替换,引用命令的执行结果;命令替换的另外一符号:$(命令);
命令替换: $(COMMAND), 反引号:`COMMAND`
把命令中某个子命令替换为其执行结果的过程
echo "the current directory is /etc/sysconfig."
echo "the current directory is $(pwd)."
示例:
变量替换:
引用变量进行替换的标准形式为:${VAR_NAME},这里的花括号{}通常可以被省略。
变量替换还有一些其他的形式,可以应用于不同的场景:
${VAR_NAME:=word} 如果变量已经被赋值了,则显示原来的值,如果变量是空,则这里冒号后面的值不仅作为默认值,并且会保存在变量中。
示例:
${VAR_NAME:?word} 如果变量已经被赋值了,则显示原来的值,如果变量是空,或没有声明变量,则问号?后面的值会定向至标准错误输出
示例:
${VAR_NAME:-word} 如果没有定义变量或变量的值为空,则变量名后面用使用冒号加一个值,该值会作为变量的默认值使用;如果变量已经被赋值了,则冒号后的默认值不会替换原有的值。
示例:
${VAR_NAME:+word} 如果变量没有声明或值为空,则不作任何操作;如果变量已经赋值了,则用加号+后面的值会替换原来赋的值(仅时临时替换,不保存至变量)
示例:
如何查看shell中的变量:
查看所有变量:set
查看所有环境变量:env, printenv, export
What is shell Script
<<======================================【SHELL脚本】======================================>>
shell脚本:
shell脚本语言是弱类型语言
shell脚本是文本文件,简单说,脚本就是数条可执行语句的罗列。
运行脚本,事实上是运行一个bash进程,此进程负责从脚本文件中读取一个执行逻辑
执行脚本的几种方式:
1、bash scripts-name 或 sh scripts-name
2、PATH/script-name 或 cd到脚本所在目录 ./script-name
3、source script-name 或 .script-name
(用此方式执行可以把脚本中的变量和函数导入到当前shell中)
/etc/init.d/functions 函数:action
shebang:
几乎每一个可执行程序的初始位置都有一个 magic number(魔数),用来标识本程序的格式。
Linux上编译的程序无法在Windows上执行,是因为ABI(Application BinaryInterface:应用程序二进制接口)不兼容。通常在Linux上编译的程序采用的是ELF格式,使用file命令可查看文件的类型:
因此,shell脚本也需要指定具体的解释器,否则无法确定用什么解释器,从而会导致无法执行。
在编写脚本时,第一行会用来指定执行该脚本的解释器,增加的这一行在脚本语言中称为 shebang。
目的为告诉内核是否可以执行下面的内容。
shell脚本规范:
1、开头:shebang
2、版权等注释信息:
#Date
#Author
#Mial
#Function
#version
3、脚本中不要用中文注释
4、脚本文件以.sh为后缀
5、成对的符号和流程控制语句一次书写完,再添加内容,避免遗漏
6、通过缩进让代码易读
在面向过程的编程语言中,语言控制结构主要有以下三种:
顺序执行:默认法则,逐条执行各语句;
选择执行:分支,条件判断,符合条件的分支予以执行;不符合则略过;
循环执行:将同一段代码反复执行有限次,所以,循环必须有退出条件,否则将陷入死循环;
条件测试
bash的条件测试主要有以下3类:
整数测试:比较两个整数谁大谁小,是否相等;
字符测试:比较两个字符串是否相等;
文件测试:测试某个文件是否具有读权限、写权限、执行权限等;
(1) 根据运行的命令的状态结果判断
(2) 在bash中进行条件测试的方式通常有三种:
test EXPRESSION
[ EXPRESSION ] ==>两边必须要有空格,否则语法错误
[[ EXPRESSION ]] ==>两边必须要有空格,否则语法错误
其中"["是启动测试命令,但要求在expression后要有一个"]"与其配对。使用该命令要特别注意"["后和"]"前的空格必不可少。
字符串比较时建议字符串变量要使用双引号,即使变量为空,也要使用双引号。
所有的测试条件都通过布尔值:(真、假) 来判定测试结果
真,假 (对于命令状态返回值来讲,0是真,其他数值都是假)
通过 echo $? 可获得上一条命令的执行状态;
状态用数字来表示:0-255;
0: 成功
1-255: 失败 (1、2、127 是系统预留的)
整数测试: A=100 B=101
[[ "$A" -gt "$B" ]]: 测试A的变量赋值是否大于B的变量赋值,是则为"真",否则为"假"
[[ "$A" -ge "$B" ]]: 测试A的变量赋值是否大于等于B的变量赋值,是则为"真",否则为"假"
[[ "$A" -lt "$B" ]]: 测试A的变量赋值是否小于B的变量赋值,是则为"真",否则为"假"
[[ "$A" -le "$B" ]]: 测试A的变量赋值是否小于等于B的变量赋值,是则为"真",否则为"假"
[[ "$A" -eq "$B" ]]: 测试A的变量赋值是否等于B的变量赋值,是则为"真",否则为"假"
[[ "$A" -ne "$B" ]]: 测试A的变量赋值是否不等于B的变量赋值,是则为"真",否则为"假"
示例:
字符串测试:
ASCII数值越大,字符比较时其值越大
[[ ABC > ABC ]]: 左侧字符是否大于右侧字符
[[ ABC < ABC ]]: 左侧字符是否小于右侧字符
[[ ABC == ABC ]]: 左侧字符是否等于右侧字符
[[ ABC != ABC ]]: 左侧字符是否不等于右侧字符
[[ ABC =~ C ]]: 左侧字符串能否被右侧模式所匹配
示例:
单目测试:
只测试一个变量
[ -z "$name" ]: 测试变量赋值是否为空,空则为"真",否则为"假"
[ -n "$name" ]: 测试变量赋值是否不空,不空则"真",空则为"假"
示例:
文件测试:
测试文件的存在性以及属性:
-a /path/to/file:测试文件是否存在,存在为"真",否则为"假"
-e /path/to/file:测试文件是否存在,存在为"真",否则为"假"
-f /path/to/file:测试文件是否存在且为普通文件
-d /path/to/file:测试文件是否存在且为目录文件
-h /path/to/file:测试文件是否存在且为符号链接文件
-L /path/to/file:测试文件是否存在且为符号链接文件
-b /path/to/file:测试文件是否存在且为块设备文件
-c /path/to/file:测试文件是否存在且为字符设备文件
-S /path/to/file:测试文件是否存在且为套接字文件
-p /path/to/file:测试文件是否存在且为管道文件
-s /path/to/file:测试文件是否存在并且不空
-r /path/to/file:当前用户对文件是否拥有读权限
-w /path/to/file:当前用户对文件是否拥有写权限
-x /path/to/file:当前用户对文件是否拥有执行权限
-u /path/to/file:文件是否拥有SUID权限
-g /path/to/file:文件是否拥有SGID权限
-K /path/to/file:文件是否拥有sticky权限
-O /path/to/file:当前用户是否为指定文件的属主
-G /path/to/file:当前用户是否为指定文件的属组
双目操作符:
[ "$file1" -nt "$file2" ]: file1的最近一次修改时间戳是否晚于file2
[ "$file1" -ot "$file2" ]: file1的最近一次修改时间戳是否早于file2
[ "$file1" -ef "$file2" ]: file1与file2是否指向了同一个inode,测试二者是否为硬链接
示例:
wKiom1X3KrDByM_YAAH3x-PPoFA670.jpg
总结:
★关于条件测试,单中括号 [ ] 与双中括号 [[ ]] 的区别:
通常,在比较变量赋值时建议使用 [ ],比较变量的赋值时,变量务必加双引号,
在比较纯字符串时建议使用[[ ]],字符串比较,比较符号两端最好都有空格
在[[]]中可以使用通配符进行匹配。&& || > < =~等符号可以应用与[[]]中,但不能用于[]中
字符串测试:
=比较两个字符串是否相同,与==等价,比如:if [ "$a" = "$b"],变量要加双引号
若字符串中间有空格或*号等特殊符号时就容易出错,因此推荐使用格式:[ "${a}"="${b}" ]
常用字符串测试操作符:
-z "字符串" 若串长度为0则真,不为0则假,
如: [ -z "$abc" ]
-n "字符串" 若串长度不为0则真,为0则为假
如: [ -n "$abc" ]
[[ "串1"="串2" ]] 若串1等于串2则真,可以使用==代替=
[[ "串1"!="串2" ]] 若串1不等于串2则真, 但不能用!==代替!=
<<====================================【组合条件测试】====================================>>
组合条件测试
条件间逻辑运算:
与:多个条件要同时满足
或:多个条件满足其一即可
非:对指定的条件取反
表达式组合:
与: [[ CONDITION1 -a CONDITION2 ]]
或: [[ CONDITION1 -o CONDITION2 ]]
非: [ ! CONDITION ]
示例:
wKioL1X3LOSgDs9YAAGKBK7DYM4925.jpg
命令组合:
与: COMMAND1 && COMMAND2 <-- [ EXPR1 ] && [ EXPR2 ]
或: COMMAND1 || COMMAND2
非: ! COMMAND
逻辑运算:
与运算:(假和任何数相与都得假)
真 && 真 = 真
真 && 假 = 假
假 && 真 = 假
假 && 假 = 假
或运算:(真和任何数相或都得真)
真 || 真 = 真
真 || 假 = 真
假 || 真 = 真
假 || 假 = 假
非运算:(取反面)
! 真 = 假
! 假 = 真
短路操作符:对条件本身做逻辑运算
与:条件1 && 条件2
条件1为假,则最终结果一定为假,因此,条件2将不执行;
条件1为真,则最终结果取决于后面条件,因此,条件2必须执行;
或:条件1 || 条件2
条件1为真,则最终结果一定为真,因此,条件2将不再执行;
条件1为假,则最终结果取决于后面条件,因此,条件2必须执行;
非: ! 条件
示例:
id一个用户名,如果执行成功则显示该用户存在,如果id命令没有执行成功,则显示该用户不存在。
id $userName &> /dev/null&& echo "$userNmae exist." || echo "$userName notexist"
wKiom1X3KrCgvKY-AACQau6J03c915.jpg
3 总结课程所讲的所有循环语句、条件判断的使用方法及其相关示例;(if (jpg|png is not exist);echo ”You say a XX“)
流程控制
循环语句:for, while, until
循环:将循环体代码执行0、1或多次
进入条件:进入循环的条件
退出条件:循环终止的条件
<<========================================【for循环】========================================>>
for循环:
for VARIABLE in LIST; do
循环体
done
进入条件:列表非空
退出条件:当列表遍历结束
LIST: 是由一个或多个空格或换行符分隔开的字符串组成:
把列表的每个字符串逐个赋值给VARIABLE表示的变量
LIST的生成方法:
(1) 整数列表
(a) {start..end}
(b) $(seq [start[[step]]end])
(2) 直接给出列表
(3) glob
(4) 根据命令生成
示例:
使用for循环添加10个用户,user1-user10
运行脚本测试:
<<======================================【while循环】======================================>>
while循环:
while CONDITION; do
循环体
控制变量的修正表达式
done
进入条件:当CONDITION为"真";
退出条件:当CONDITION为"假";
示例1:
使用while循环求100以内所有正整数之和
运行脚本测试:
示例2:
使用while循环打印九九乘法表
运行脚本测试:
<<======================================【until循环】======================================>>
until循环:
until CONDITION; do
循环体
循环控制变量的修正表达式
done
进入条件:当CONDITION为"假"时
退出条件:当CONDITION为"真"时
示例:
使用until循环求100以内所有正整数之和
运行脚本测试:
<<======================================【循环控制】======================================>>
循环控制:
continue [n]: 提前结束本轮循环,而直接进入下一轮
break [n]: 提前结束循环
使用格式:
while CONDITION; do
if CONDITION2; then
break [n]
fi
done
while CONDITION; do
...
if CONDITION2; then
continue [n]
fi
....
done
死循环:
while ture; do
循环体
if CONDITION; then
break
fi
done
until false; do
循环体
if CONDITION; then
break
fi
done
示例1:
求100以内所有偶数之和
运行脚本测试:
示例2:
给脚本传递一个用户命名,如果该用户登录到该系统,则显示其已登录,如果没有检测到该用户
登录,则显示该用户未登录,休眠3秒后继续检测,如此重复,直到用户登录为止才结束循环。
运行脚本测试:
登录用户:
此时,检测到该用户已登录,则显示用户已登录,然后结束循环
<<======================================【特殊用法】======================================>>
while、for循环的特殊用法
while循环的特殊用法:
遍历文件的每一行:
while read VARIABLE; do
循环体
done < /PATH/FROM/SOME_FILE
示例:
找出UID为偶数的所有用户,显示整行用户信息
运行脚本测试:
for循环的特殊用法:
for ((expr1;expr2;expr3)); do
循环体
done
expr1:定义控制变量,并初始赋值
expr2:循环控制条件
进入条件:控制条件为"真"
退出条件:控制条件为"假"
expr3:修正控制变量
示例:
给变量i赋值=1,在变量i的赋值小于30时,每次往自身+1,直到i的赋值等于30时退出循环,
每一次循环都与数字5相乘,得出以下结果。
4、总结文本处理工具sed及awk的用法;(必须附带示例)
========== Sed =============
sed [options] ‘command’ file
首先准备如下文件:
删除指定的行 使用d命令
例子1:
例子2: 删除1-3行
查找替换,使用s命令
例子1: 替换所有
============= awk ================
首先准备如下文件:
例子1:打印指定区域
//只打印姓名和电话号码
//打印全部
例子2: 指定打印分隔符
//指定“.”作为分隔符 $1就是.之前的区域
5 写一个脚本:如果某路径不存在,则将其创建为目录;否则显示其存在,并显示内容类型;(不要怀疑,就是这么简单)
#!/bin/bash
#
filename="/tmp/x/y/z/testdir"
if [ -e $filename ]; then
echo "$filename exists."
file $filename
else
mkdir -p $filename
fi
6 写一个脚本,完成如下功能;判断给定的两个数值,孰大孰小;给定数值的方法:脚本参数,命令交互;(使用read,依然如此简单)
1 脚本参数方法
2命令交互方法
7 求100以内所有奇数之和(至少用3种方法。是的这是我们的作业^_^)
第1种:
#!/bin/bash
#
declare -i sum=0
for i in $(seq 1 2 100); do
sum=$(($sum+$i))
done
echo "Even sum: $sum."
第2种:
#!/bin/bash
#
declare -i sum=0
for i in {1..100}; do
if [ $[$i%2] -ne 0 ]; then
sum=$[$sum+$i]
fi
done
echo "Even sum: $sum."
第3种:
1 #!/bin/bash
2 #
3 declare -i sum=0
4 declare -i i=1
5
6 while [ $i -le 100 ];do
7 let sum+=$i
8 let i+=2
9 done
10 echo "Sum: $sum."
~
8、写一个脚本实现如下功能:
(1) 传递两个文本文件路径给脚本;
(2) 显示两个文件中空白行数较多的文件及其空白行的个数;
(3) 显示两个文件中总行数较多的文件及其总行数;
#!/bin/bash
#
read -p "plz input two file or dir path:" -t 50 f1 f2
if [ -z $f1 -o -z $f2 ]
then
echo "Usg:$0 /path/file1 /path/file2"
exit 1
fi
if [ ! -e $f1 -o ! -e $f2 ]
then
echo "$f1 or $f2 not exist"
exit 2
fi
f1_s=`grep '^$' $f1|wc -l`
f2_s=`grep '^$' $f2|wc -l`
if [ $f1_s -gt $f2_s ]
then
echo "space_max: $f1 : $f1_s;"
elif [ $f1_s -lt $f2_s ]
then
echo "space_max: $f2 : $f2_s;"
else
echo "$f1,$f2 space lines is eq;space_line= $f1_s"
fi
f1_lines=`wc -l $f1|cut -d" " -f1`
f2_lines=`wc -l $f2|cut -d" " -f1`
if [ $f1_lines -gt $f2_lines ]
then
echo "max_lines: $f1 :$f1_lines ;"
elif [ $f1_lines -lt $f2_lines ]
then
echo "max_lines: $f2 : $f2_lines ;"
else
echo "$f1,$f2 lines is eq"
echo "$f1 lines: $f1_lines , space_lines: $f1_s"
echo "$f2 lines: $f2_lines , space_lines: $f2_s"
fi
9、写一个脚本
(1) 提示用户输入一个字符串;
(2) 判断:
如果输入的是quit,则退出脚本;
否则,则显示其输入的字符串内容;
10 写一个脚本,打印2^n表;n等于一个用户输入的值;(不好意思,我调皮了)
1 #!/bin/bash
2 #
3
4 read -p "Plz input a integer: " -t 10 num1
5
6
7 if [ -z "$num1" ];then
8 echo "Plz input a integer"
9 exit 1
10 fi
11
12 for i in $(seq 0 $num1); do
13 echo "2^$i = $[2**i]"
14 done
11、写一个脚本,写这么几个函数:函数1、实现给定的两个数值的之和;函数2、取给定两个数值的最大公约数;函数3、取给定两个数值的最小公倍数;关于函数的选定、两个数值的大小都将通过交互式输入来提供。
#!/bin/bash
#
if [[ $# -le 2 ]];then
echo "plz input two number and use space to isolation them!"
fi
function add() {
echo "The two num sum:$1+$2=`expr $1 + $2`"
}
add $1 $2
declare -i big
declare -i sma
if [ $1 -gt $2 ];then
big=$1
sma=$2
else
big=$2
sma=$1
fi
gcdlcm(){
i=1 #定义一个循环变量
GCD=1 #定义最大公约数
LCM=1 #定义最小公倍数
btmp=1 #定义用户输入的较大的一个变量除以循环变量的值
stmp=1 #定义用户输入的较小的一个变量除以循环变量的值
while [ $i -le $sma ];do #定义循环条件,循环变量小于或等于用户输入的较小的变量
btmp=`expr $big % $i` #求值
stmp=`expr $sma % $i` #求值
if [ $btmp -eq 0 ];then #判断值得余数是否为0
if [ $stmp -eq 0 ];then #同上
gcd=$i #如果值得余数为0,则获取最大公约数的值
fi #判断结束
fi
i=`expr $i + 1` #i变量循环,直到i等于用户输入的较小的数为止退出循环。
done #当i=$sma,退出循环
lcm=`expr $sma / $gcd` #根据最小公倍数公式求值
lcm=`expr $lcm \* $big` #同上,求最小公倍数公式为:lcm=$sma*$big%gcd
echo "lcm:$lcm" #输出lcm值
echo "gcd:$gcd" #输出gcd值
}