一、作业(练习)内容:
1、描述shell程序的运行原理(可附带必要的图形说明);
shell的解释:
Shell的作用是linux操作系统的外壳,为用户提供使用操作系统的接口。它是命令语言、命令解释程序及程序设计语言的统称。
Shell会先确认用户的词语分析,来理解命令,选项,参数来进行解析。Shell中有内建命令,还有外部命令;流程的过如下:
(1)读取用户由键盘输入的命令;
(2)分析语法,命令,参数,然后配置参数;
(3)终端进程调用fork( )建立一个子进程;
(4)进程创建完成后,内部运行的指令提交给内核来完成任务;
(5)代码执行结束后,进程通知shell,它的任务已完成,子进程中止;
(6)shell接到退出指令,将显示下一个提示符,等待接受下一条命令;
2、总结shell编程中所涉及到的所有知识点(如:变量、语法、命令状态等等等,要带图的哟);
shell 的变量:
Shell中的变量的意思就是可变化的量,程序运行到进程以后再内存中申请的内存空间,这个空间可以反复存储与修改数据,另外也可命名的存储空间。
变量的分类:
本地变量:
只对当前shell进程有效的变量,对其他shell进程无效,包括当前shell进程的子进程。
定义本地变量: VAR_NAME=VALUE
变量名:包含数字,字母和下划线,且不能以数字开头;
变量赋值:向变量的存储空间保存数据;
变量引用:${VAR_NAME}
“”:弱引用,里面的变量会被替换;
‘’:强引用,里面的所有祖父都是字面量,直接输出;
声明数值类型:
declare -i name{=value}
实例:强引用,弱引用,以及定义的方法:
环境变量:
对当前shell进程及其子shell有效,对其他shell进程无效。
定义环境变量: export VAR_NAME=VALUE
导出: export VAR_NAME
查看环境变量:env ,printenv,export
添加PATH环境变量,第1种方法:(用户注销就失效)
[[email protected]_web_s1 ~]# export PATH=/usr/local/webserver/mysql/bin:$PATH
第2种方法:
# vim /etc/profile
在最后,添加:
export PATH="$PATH:/tmp/hzm/"
保存,退出,然后运行:
#source /etc/profile
局部变量:
对shell脚本中某代码片段有效,通常用于函数本地:
定义局部变量:Loacl export VAR_NAME=VALUE
位置参数与特殊变量:
$#:传递给脚本的参数数量;
$0 脚本的名称;
$1,$2,$3.... 第一个参数,第二个参数,第三个参数;
[email protected] :所有参数的列表;
实例:用脚本输出方式展现各参数的意义:
语法:
1. 第一行必须是"#!/bin/sh"
#!/bin/sh"是对shell的声明,说明你所用的是那种类型的shell及其路径所在;
如果没有声明,则脚本将在默认的shell中执行,默认shell是由用户所在的系统定义为执行shell脚本的shell.
2.注释:开头为#
3.脚本内容:
实例:语法开头,#为注释内容,下面是脚本内容:
bash -n 检查脚本是否有语法错误
bash -x 显示脚本执行过程
命令状态:
0 :成功执行:检查、/etc/passwd目录是否存在,如果存在状态值返回0
非0 : 执行过程中出现异常或非正常退出;(状态值可以在脚本中作为结束脚本来使用)
$? 可以查看 最后一条命令的返回值 该变量可以在shell 脚本中的任何地方使用.
测试表达式:
[ EXPRESSION ]
整数测试:隐含做数值大小比较,所以不要给变量引用加引号;
实例:先定义变量:A=4,B=6
A -gt B 是否大于(echo $? 返回为1的状态为否定的,所以A不大于B)
A -ge B是否大于等于
A -lt B 是否小于
A -le B是否小于等于
A -eq B 是否等于
A -ne B 是否不等于
字符串比较:ASCII数值越大,所以相同的字母值越大;
> 是否大于
< 是否小于
== 是否等于:$A == $B
!= 是否不等于
-z 测试是否为空:空着为真,否则为假
-n 测试是否不空:不空为真,否则为假
文件测试:($? 为0存在,1则不存在)
-e:是否存在并且为文件存在:
-f:是否存在并且为普通文件:
-d 是否存在并且为目录
-h:是否存在并且为链接文件
-L:同上
-b:是否为块设备文件
-c:是否存在并且为字符设备文件
-S 是否存在并且为套接字文件
-p:是否存在且为管道文件
读写权限检测:
-r:当前用户是否拥有读权限
-w:当前用户是否拥有写权限
-x:当前用户是否拥有执行权限
-u:当前用户是否拥有suid权限
-k:文件是否拥有sticky权限
-g:文件是否有sgid
-O:当前用户是否为指定的属主
-G:当前用户是否为指定的属组
双目操作
A -nt B:是否晚于
A -ot B:A是否旧于B
A -ef B:是否指向同一个文件的硬链接
算数运算方式:
1.$[$A+$B]
2.$(($A+$B))
3.Let variable=$A+$B
4.expr $A + $B
3、总结课程所讲的所有循环语句、条件判断的使用方法及其相关示例;(if (jpg|png is not exist);echo ”You say a XX“)
if语句结构
单分之if:
if then, if true-分支 fi
if:
实例:如果用户root存在,则输出该用户存在;
双分支if:
if then, if true分支 else if false分支 fi if
实例:如果该用户存在,输出user存在,否则该用户不存在;
多分支if语句:
if elif ;then fi
实例:给脚本两个参数判断 a 与b的比较:
#!/bin/bash read -p "please give two number:" a b if [ $a -eq $b ] then echo "$a is equal to $b" elif [ $a -gt $b ] then echo "$a is greater than $b" elif [ $a -lt $b ] then echo "$a is less than $b" else echo "please give two number" fi
for循环
for 变量 in LIST;do
循环体
done
LIST:是有一个或多个空格分隔开的字符串组成;把列表的值逐一赋值给变量;
实例1:在/tmp目录下创建1-10目录;
#!/bin/bash for i in $( seq 1 10 );do mkdir -p /tmp/${k} done
实例2:for循环嵌套,创建文件,创建1-10个目录,并且每个文件里面创建1-10个目录
#!/bin/bash for k in $( seq 1 10 );do mkdir -p /tmp/aaa${k} for l in $( seq 1 10 );do mkdir -p /tmp/aaa$[k]/bbb${l} done done
结果:
实例3:计算数值的特殊用法
#!/bin/bash read -p "please give number:" s1 declare -i sum=0 for ((i=1;i<=$s1;i++));do sum=$[$i+$s1] done echo "the number:$sum"
结果:
组合判断:&& ||
cmd1 && cmd2 : 如果cmd1执行完毕而且正确,则开始执行cmd2
如果cmd1执行完毕且错误,则cmd2不执行
cmd1 || cmd2 :如果cmd1执行完毕且正确,则cmd2不执行
如果cmd1执行完毕错误,则开始执行cmd2
实例:若文件目录存在则创建123文件:
若文件目录不存在则直接告诉没有目录,而且不执行后面的命令;
实例2:如果文件目录不存在则执行后面的命令,如果在执行一次该命令就会报错,因为该文件已经存在所以后面的命令不执行;
while until循环
语句格式:
while [判断式];do
程序内容
done 循环结束
实例:求100以内整数之和(经典案例拿来引用)
#!/bin/bash declare -i sum=0 declare -i i=1 while [ $i -le 100 ]; do let sum+=$i let i++ done echo "$sum"
结果:
until循环
语法格式:
与while相反
until condition;do
循环体
循环控制变量的修正表达式
done
进入条件:当condition失败时
退出条件:当condition成功时
实例:求100以内正整数之和
#!/bin/bashdeclare -i sum=0declare -i i=1until [ $i -gt 100 ]; do let sum+=$i let i++doneecho "$sum"
结果:
循环控制:
contion:提前结束本轮循环,而直接进入下一轮
break:提前终止循环
死循环:
Whine true;do
循环体
if condition;thenfidone#!/bin/bashusername=hzmwhile true;do if who | grep "$username" &> /dev/null;then echo "$username is logged" break fi sleep 3done
结果:当hzm用户登录的时候脚本检测到该用户,并且执行break退出;
while特殊用法 :
while read VARIABLE;do
循环体
done < /PATH/FROM/SOME_FILE
case 循环
case $变量 in
Parttern1)
分支
;;
实例:
#!/bin/bash read -p "please give number:" num case $num in "one") echo "this is one" ;; "two") echo "this is two" ;; "tree") echo "this is three" ;; *) echo "Usage $0 {one|two|three}" ;; esac
结果:
函数库
语法:
function:把一段具有独立功能代码封装在一起,并给与命名:后续用到时,可直接通过给定函数名来调用整体代码;
用法:
name () {
函数体
}
调用方法:
name[参数1,参数2]
实例:调用函数来ping一个B类地址
#!/bin/bash
#
PING() {
if ping -c 1 -w 1 $1 &> /dev/null; then
return 0
else
return 1
fi
}
HZM="210.14"
(
for S in {1..5}; do
for I in {1..5}; do
if PING $HZM.$S.$I; then
echo "$HZM.$S.$I is up." >> /root/456.txt
else
echo "$HZM.$S.$I is down." >> /root/789.txt
fi
done
done
)&
wait
结果:显示在线的网址输出到456.txt中,不在线的输出到789.txt中;
函数模块化编程:
4、写一个脚本:如果某路径不存在,则将其创建为目录;否则显示其存在,并显示内容类型;(不要怀疑,就是这么简单)
方法:
#!/bin/bash FILEtest=/tmp/hzm if [ -e $FILEtest ]; then echo "$FILEtest exist" file $FILEtest else mkdir -p $FILEtest fi
结果:
[[email protected] ~]# bash -x test.sh
+ FILEtest=/tmp/hzm
+ ‘[‘ -e /tmp/hzm ‘]‘
+ echo ‘/tmp/hzm exist‘
/tmp/hzm exist
+ file /tmp/hzm
/tmp/hzm: directory
5、写一个脚本,完成如下功能;判断给定的两个数值,孰大孰小;给定数值的方法:脚本参数,命令交互;(使用read,依然如此简单)
方法:
#!/bin/bash read -p "Please enter two values: " -t 10 values1 values2 if [ -z "$values1" ]; then echo "Please enter two values" exit 1 fi if [ -z "$values2" ]; then echo "Plz give tow integers." exit 1 fi if [ $values1 -ge $values2 ]; then echo "Max: $values1, Min: $values2." else echo "Max: $values2, Min: $values1." fi
结果:
[[email protected] ~]# sh number.sh
Please enter two values: 4 5
Max: 5, Min: 4.
[[email protected] ~]#
6、求100以内所有奇数之和(至少用3种方法。是的这是我们的作业^_^)
第一种:
#!/bin/bash
declare -i sum=0
for i in $(seq 1 2 100); do
sum=$[$sum+$i]
done
echo "$sum"
结果:
[[email protected] ~]# sh 2.sh
2500
[[email protected] ~]#
第二种:
#!/bin/bash
declare -i sum=0
declare -i i=1
while [ $i -le 100 ];do
if [ $[$i%2] -ne 0 ];then
let sum+=$i
fi
let i++
done
echo $sum
结果:
[[email protected] ~]# sh 2.sh
2500
[[email protected] ~]#
第三种:
方法:
#!/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"
结果:
[[email protected] ~]# sh 1.sh
Even sum: 2500
[[email protected] ~]#
7、写一个脚本实现如下功能:
(1) 传递两个文本文件路径给脚本;
(2) 显示两个文件中空白行数较多的文件及其空白行的个数;
(3) 显示两个文件中总行数较多的文件及其总行数;
方法:
#!/bin/bash
if [ $# -lt 2 ];then
echo "two"
exit 1
fi
if [ $(grep "^$" $1 | wc -l) -gt $(grep "^$" $2 | wc -l) ];then
echo "more blank line file is $1" && echo "there are $(grep "^$" $1 | wc -l) blank lines"
else
echo "more blank line file is $2" && echo "there are $(grep "^$" $2 | wc -l) blank lines"
fi
if [ $(wc -l $1 | cut -d" " -f1) -gt $(wc -l $2 | cut -d" " -f1) ];then
echo "more line is $1" && echo "File number: $(wc -l $1)"
else
echo "more line is $2" && echo "File number: $(wc -l $2)"
fi
结果:
[[email protected]ost ~]# sh 3.sh /etc/fstab /etc/init.d/functions
more blank line file is /etc/init.d/functions
there are 76 blank lines
more line is /etc/init.d/functions
File number: 834 /etc/init.d/functions
[[email protected] ~]#
8、写一个脚本
(1) 提示用户输入一个字符串;
(2) 判断:
如果输入的是quit,则退出脚本;
否则,则显示其输入的字符串内容;
方法:
#!/bin/bash
read -p "please give Parameter:" -t 10 par
if [ -z $par ]; then
echo"please give Parameter:"
exit 1
fi
if [ $par == ‘quit‘ ]; then
exit 1
else
echo $par
fi
结果:输入‘quit’字符直接退出:
[[email protected] ~]# sh 4.sh
please give Parameter:quit
[[email protected] ~]#
输入其他字符:
[[email protected] ~]# sh 4.sh
please give Parameter:kkk
kkk
[[email protected] ~]#
9、写一个脚本,打印2^n表;n等于一个用户输入的值;(不好意思,我调皮了)
方法:
#!/bin/bash
read -p "please input number:" -t 10 num
if [ -z $num ]; then
exit 1
fi
count=2
for i in `seq 0 $num`;do
if [ $i -eq 0 ];then
echo "1"
elif [ $i -eq 1 ];then
echo "2"
else
count+=x2
echo "$count=$[2**$i]"
fi
done
结果:
10、写一个脚本,写这么几个函数:函数1、实现给定的两个数值的之和;函数2、取给定两个数值的最大公约数;函数3、取给定两个数值的最小公倍数;关于函数的选定、两个数值都将通过脚本参数进行输入。
#!/bin/bash
if [ $# -lt 2 ];then
echo "two"
exit 1
sumnu() {
sum=$[$1+$2]
echo "the sum is $sum"
}
取两个值得最大公约数:
方法1:函数库内部调用本身(网上高手写的,思路很好拿来学习了^_^)
#!/bin/bash
#!/bin/sh
read -p "Input two positive integers: " a b
# Greatest Common Divisor
gcd()
{
if [ $2 -eq 0 ]; then
echo $1
else
gcd $2 `expr $1 % $2`
fi
}
gcd $a $b
方法2:
求最大公约数与最小公倍数的方法:
#!/bin/bash
if [ $# -ne 2 ];then
echo "USAGE:$0 integer1 integer2"
exit
fi
GCD()
{
a=$1
b=$2
if [ $a -lt $b ];then
max=$b
min=$a
else
max=$a
min=$b
fi
if [ $[$max%$min] -ne 0 ];then
GCD $min $[$max%$min]
fi
gcd=$min
}
LCM()
{
GCD $1 $2
b=$[$1*$2]]
lcm=$[$b/$gcd]
}
GCD $1 $2
LCM $1 $2
echo "gcd is $gcd, lcm is $lcm"
sed
命令解释:
是一种非交互式流编辑器,通过多种转换修改流经它的文本。默认情况下sed不会改变原文件本身,而只是对流经sed命令得文本修改,并将修改后的结果打印到屏幕。
Sed处理文本是以行为单位,每处理一行就立即打印出来,然后处理下一行,直到文本结束。
语法:
sed [options] file
选项:
d:删除 ---使用数字表示有多少行, 比如”1,5” “1 ~ 2”
实例:删除第3行。
实例2:删除1到3行的内容。
实例3:删除2到最后一行的内容。
实例4:删除最后一行的内容。
实例5:删除包含nine字符的行。
实例6:sed也支持正则表达式:比如”^$” 删除空行。
s:替换
参数:
-U:将\U后面的字符全部转换为大写
-u:吧\u后面第一个字符变成大写
-E:代表终止
实例1:将文本中is替换成to;
实例2:将文本中第二个单词is替换成to;
实例3:将文本中is全局替换成to;
实例4:替换第3行的This,替换为your;
替换is大写或者小写的字符,转换为your;
利用正则表达式替换[ ]内的字符为your;
另外一种做法,将[]内的内容替换成大写,利用-U来实现,反之-L转换为小写;
那如果只是转换一个字符呢,就利用-u来实现;
分组:(group)替换,于正则的用法一致;
a:在指定行下一行追加;
I:在指定行上一行追加;
c:命令是匹配条件的内容替换;
y:匹配内容替换为另外内容;
实例:在网卡目录下面最后一行增加dns1;
实例2:将文中i替换成t,s替换成o
i:文本修改;
实例:使用i命令在第2行前插入wo字符;
实例2:使用a命令在第二行后面插入wo字符;
实例3:在匹配的字符前面插入字符;
实例4:复杂一点的方法:将[]内的内容替换成yyYYe;
实例5:将/etc/sysconfig/network-scripts/ifcfg-eth0目录下的onboot改成off;
读入文本:
r:在匹配文中下一行添加另外的文件内容;
打印:-n是只显示参数的内容;
x:保持空间与模式空间互换:
h:把模式空间的内容拷贝到保持空间去:
H:把模式空间的内容追加到保持空间去:
g:把保持空间的内容写入到模式空间;
G:把保持空间的内容追加到模式空间;
awk
命令解释:
相比较sed的逐行处理文本,awk更倾向于将一行分割为字段处理;
工作机制是把指定的文本切成字段来做处理;
变量:1.内置变量;2自定义变量;
RS:输入行分隔符;
OFS:输出时的字段分隔符;
ORS:输出时的行分隔符;
语法格式:
awk [options] ‘program‘ file file
awk [options]‘{pattern + action}‘ {filenames}
常用命令:
print:简单输出命令
1.各项目之间使用逗号分隔,而输出时则使用输出分隔符分割;
2.输出的各item可以使用字符串或数值,当前记录字段,变量或awk得表达式;数值会被隐式转换为字符串后输出;
3.print后面item如果省略,相当于print $0:输出空白;
print item1 item2(awk读取默认是空白作为分隔符,也可以指定分隔符)
例如: this is a test----->$0 被分割为4个字符:
$1 $2 $3 $4
FS:输入时得字段分隔符;
RS:输入行分隔符;
OFS:输出时的字段分隔符;
ORS: 输出时的行分隔符;
NF:分隔字段数;
NR:行数;所有文件一并统计;
FNR:行数,个文件分别统计;
实例1:打印指定分隔符,能显示awk特性;
实例2:-F(指定分隔符)打印指定位置分隔符;
实例3:利用NF参数打印显示有几个域;
实例4:$NF打印最后一个域的字符;如果是倒数第2个域就-1;
实例5:NR:行数,对文件中的行做统计;
实例6:FNR:对两个文件的内容分别计算行数;
内置变量:
OFS:输出分隔符
实例5:利用输出分隔符来给每一个空格加上:
-v:给变量赋值;
FS=:输入分隔符;
OFS=# 输出分隔符;
-v:赋值
赋值给test=hi,同时在文本中加入变量;
printf format item1,item2....
format格式的指示符都%开头u,后跟一个字符:
%c:显示字符的ASCII码;
%d,%i:十进制整数;
%e,%E:科学记数法显示值;
%f:显示浮点数;
%g:%G:以科学计数法格式或浮点数格式显示数值;
$s:显示字符串;
%u:显示无符号整数;
%%:显示%自身;
修饰符:
#:显示宽度
-:左对齐
+:显示数值的符号;
.#:取至精度
实例1:
实例2:上个实例中添加上7,就是给特定字符宽度;
算术运算:+,-,*,/,%,-x,+x
赋值操作:=,+=,-=,如果自身是等于号/=/
awk的if条件表达式
selector?if-ture-expression:if--false-expression
实例:根据if条件表达式来做一个判断实例:
模式:
1.正则表达式:/正则表达式/;
2.表达式:0或1,货非空的字符串满足条件;
3.BEGIN:BEGIN{语句}....END{语句};仅在awk命令program运行之前运行一次,或者之后end之后执行一次;
4.组合模式:(&&),或(||),非(|);
实例1:正则表达式:
实例2:显示匹配到正则表达式的行;
实例3:匹配数字大于等于77的数字:
实例4:利用正则做模式匹配,把用户名与bash类型匹配的显示出来;
实例5:表达行范围,NR指定行的范围;
实例6:在文本首尾,BEGIN开始显示一行内容,END末尾显示一行内容;
控制语句:
if-else:if(condition){then body}else{else body}
while: while (condition) {while body}
do-while循环:
for循环:
数组:
实例1:显示字段数大于2的行;
实例2:显示第三段数字大于66的整行内容,否则就显示行号;
实例3:利用awk语句来计算100以内正整数之和;
实例4:遍历每一行的字符,如果大于等于3就显示出来;