您的位置:首页 > 运维架构 > Shell

20150913 Linux Shell

2015-09-28 16:50 671 查看
Part 1 学习整理
第一、shell概述
Bshell是解释器
硬件—》Kernel--->库----》程序员调用库进行程序开发
守护进程,服务进程(后台运行、非交互):启动?开机时自动启动;
交互式进程:shell应用程序
广义接口:GUI,CLI
GUI
CLI:
promt
COMMAND
词法分析: 命令,选项,参数
内建命令:shell自带
外部命令:PATH环境变量所定义
fork() 创建为一个进程;系统调用的一种实现
把要运行的一系列命令,写在文件中;解释器读取文件,逐条运行。
脚本或程序源文件:文本文件,由文本文件由机器执行的方式
两种方式:
编译执行:预处理-->编译-->汇编-->链接;事先完成,结果:二进制程序文件
C, C++
解释执行:由解释器全程参与运行过程,无需要事前转换。每次读取一行,运行一行;
Python:编程库
程序控制结构,调用编程库完成程序编写;
库文件:功能模块,在编程中可调用;通过其API;
Bash:编程(交互式接口,提供编程的能力)
程序控制结构,调用机器上命令程序文件进行程序编写;例如ls、Cat等
这些命令可脱离shell执行。相关程序文件不依赖程序库
外部命令:各GNU应用程序提供
第二、程序编程方式
程序:指令+数据
算法+数据结构
过程式编程:以指令为中心,设计算法,数据服务于算法;
对象式编程:以数据为中心,设计数据结构(类),程序服务于数据结构;应用大于
bash过程式编程:
顺序执行:逐个执行
选择执行:只执行其中一个分支
循环执行:一段代码要执行0,1或多遍
编程元素:变量、流程、函数
第三:shell变量的定义
A:变量作用范围
变量:可变化的量,命名内存空间
一个脚本一个进程运行,一个进程内部多个函数,每个函数
内部可使用局部变量,作用范围某函数执行过程。
bash环境:作用范围
本地变量:当前shell进程;
环境变量:当前shell进程及其子进程;
局部变量:某个函数执行过程;
位置参数变量:在脚本中引用传递给脚本的参数;在函数中引用传递给函数的参数;
特殊变量(内建某些特殊值):$?, $*, $@, $#, $$
B:变量值类型
数值,字符;
数值:(每种类型有单独的内存存储空间)
整数
浮点数
字符:
ASCII码(7位2进制数)
数值与字符的区别:
字符:1, 2, 0(每个字符8个2进制数)
数值:120 --> 转换成2进制数(7位2进制)
变量类型的作用:
存储空间
运算
存储格式
语言对变量类型的支持力度:
强类型:C++(类型严格区分)
弱类型:变量类型不严格区分;
默认存储机制:bash为字符,也可指定为数值型
C:bash变量的定义使用
bash的变量使用特点:弱类型、无须事先声明;
1)本地变量:只在本进程有效,在父进程无效
示例:运行二个bash,第一个为父进程、第二个为子进程
父进程定义变量$animal,echo $animal输出为pig,而在
子进程运行输出echo $animal为空



name=value 如果为字符串需引号(单引号或双引号皆可)括起来,如无空格可直接使用
name: 变量名
=:赋值符号
value:值
变量名:只能包含数字、字母和下划线;且不能以数字开头;(不要使用大写开头)

引用变量:${name}, $name,返回值用echo ${name}
引用(共4种,常用三种如下):
弱引用: "", 其内部的变量引用会被替换为变量值;(变量替换会发生)
强引用:'',其变量的变量引用会保持原有字符;
命令引用:`COMMAND`, $(COMMAND),引用命令的执行结果;反引号` `
声明为整型:
declare -i name[=value]
let name=value
查看所有变量:set
生命周期:
创建:开始
销毁:(销毁法则)
自动销毁:shell进程终止;
手动销毁:unset name(变量名)
2)环境变量:
作用范围当前进程及子进程
被“导出”的本地变量
export name[=value]
declare -x name[=value]
示例:name=’obama’ #这里为本地变量
exprot name #导出后为环境变量



分别进入三个bash子进程,使用echo $name
正常可以输出相关值obama



查看所有环境变量:env, printenv, export



销毁:(手动、自动)
unset name
第四、脚本:文本文件
运行脚本:事实上是运行一个bash进程,此进程负责从脚本文件中读取一个执行逻辑,
而后由bash进程负责解析并运行此逻辑;脚本作为参数提供bash运行。
1)启动脚本:
两种方式:
(1) # bash /PATH/TO/SCRIPT_FILE bash加路径
(2) 一个执行权限, (单独运行) # ./PATH/TO/SCRIPT_FILE
语法格式:
shebang语法:第一行顶格写)
#!/bin/bash (解释器路径,运行下而脚本中内容)
第一行:顶格给出shebang
注释行:#
脚本示例:执行或者./shell名称(之前增加执行权限)



*备注:--stdin表示可以用任意文件做标准输入,这里是echo
其中第一个testuser1是为密码,后利用—stdin进行引用
2)bash的常用选项:
-n: 检查脚本中的语法错误;
-x:调试执行脚本;
bash 脚本名称:直接运行



3)命令状态结果:
bash进程用于追踪执行的命令成功与否的状态:
0: 成功
1-255:失败(其中1、2、127、63、64是bash内置其它可自定义)
特殊变量:
$?:上一条命令的执行状态结果;



布尔型:
“真”:成功
“假”:失败
自定义脚本的状态结果:
exit

注意:脚本中任何位置执行了exit命令即会终止当前shell进程;



4)条件测试:
界定程序执行环境;
(1) 根据运行的命令的状态结果; 根据结果$?返回值进行判断!结果成功或失败
(2) 测试表达式
test EXPRESSION 例如:
[ EXPRESSION ] 注意:[ ]内部前后二端有空格,无空格会提示语法 内建命令
[[ EXPRESSION ]] 同样需要空格,bshell关键字
测试表达式常规包括以下三种:
第一种:整数测试:双模操作符,隐含着做数值大小比较,所以不要给变量引用加引用
$A -gt $B:是否大于;是则为“真”,否则为“假”; A变量中的数值是否大于B变量的值



返回非0说明是假的
$A -ge $B: 是否大于等于;
$A -lt $B:是否小于; (less then)
$A -le $B: 是否小于等于;
$A -eq $B: 是否等于; (equal)
$A -ne $B:是否不等于;
第二种:字符串测试:ASCII码比较数值越大,字符比较时其值越大;
有变量双引号、无变量单引号,同时采用双引号
"$A" > "$B":是否大于;
"$A" < "$B":是否小于;
"$A" == "$B":是否等于; 比较常用



"$A" != "$B":是否不等于;
-z "$A":是否为空;空则为“真”,否则为“假”
-n "$A":是否不空;不空则“真”,空则为“假”
注意:应该使用双中括号[[ EXPRESSION ]]
第三种:文件测试:测试文件的存在性以及属性;单目操作符
-e $file: 是否存在;存在则为“真”,否则为“假”; 后面$file为文件路径
-a $file: 同上;
-f $file:文件是否存在且为普通文件;
-d $file:文件是否存在且为目录;
-h $file:是否存在且为符号链接文件;
-L $file: 同上
-b $file:是否存在且为块设备文件;
-c $file:是否存在且为字符设备文件;
-S $file:是否存在且为套接字文件;
-p $file: 是否存在且为管道文件;
第四种:权限测试
-r $file: 当前用户对文件是否拥有读权限;
-w $file:当前用户对文件是否拥有写权限;
-x $file:当前用户对文件是否拥有执行权限;
-u $file:文件是否拥有SUID权限;
-g $file:文件是否拥有SGID权限;
-k $file:文件是否拥有sticky权限;
-O $file: 当前用户是否为指定文件的属主;
-G $file: 当前用户是否为指定文件的属组;
示例:



第五种:双目操作符: (二个操作符)
$file1 -nt $file2: file1是否新于file2, file1的最近一次的修改时间戳是否晚于file2的; (new then)
$file1 -ot $file2: file1是否旧于file2, file1的最近一次的修改时间戳是否早于file2的; (old then)
$file1 -ef $file2:file1与file2是否指向了同一个inode;测试二者是否为同一个文件的硬链接;
第六种:特殊设备:
/dev/null: 空,bit buckets,吞下所有数据,并直接丢弃; ,作为输出设备使用
示例 &>/dev/null
/dev/zero:吐出一堆0;作为输入设备作用
5) bash之条件判断(选择执行):
包括顺序、选择、if/then, case ,fi结尾
单分支:
if CONDITION; then
if-true-分支
fi
多分支:
if CONDITION; then
if-true-分支
else
if-false-分支
fi
取反
! CONDITION: 取反






上述示例中如果条件为假,则不运行后续”echo $username|….”命令

练习:写一个脚本
如果某路径不存在,则将其创建为目录;否则显示其存在,并显示内容类型;

#!/bin/bash
#
filename="/tmp/x/y/z/testdir"
if [ -e $filename ]; then
echo "$filename exists."
file $filename
else
mkdir -p $filename   #-P表示父目录同时创建
fi
6)脚本参数(位置参数变量):
# ./script.sh /etc/fstab /etc/grub2.cfg (centos 7)
$0 $1 $2
位置参数变量:$1, $2, ...
${10} 二位数字即超过10时中{}
示例:判断输入的文件是否存在?如果存在则计算行数
如果不存在则输出不是文件



运行利用shell名称 filename形式 ./file2.sh /etc/fstab
./file2.sh为脚本,/etc/fstab为变量$1的值



特殊变量:判断参数是输入
$?: 命令的状态结果;
$0:表示脚本名称
$#: 传递给脚本或函数的参数的个数;
$*和$@: 引用传递给脚本或函数的参数列表;
示例:$#用于判断./shell.sh文件后面是否输入参数
当空时输出Usage:./shell.sh <file>./shell.sh后面要有参数文件路径。
exit 1条件不满足出退出当前shell脚本
当有路径参数时正常输出。



shift
:轮替
例如有三个参数 1,2,3,当启用该参数时,第一次用完后将参数1
替出,这时参数为2,3,原用参数前移一位。以此类推。
示例如下:



$*表示所有引用参数
每次引用$1后,shift后后续变量前移。分别以A,B,C输出,
$*输出最后一个C。shift 2 表示一次踢2个例如,一般用于
循环环境中。



与用户交互:
read命令: read从输入中读取保存到指定变量当中
help read查看命令
read [options] VAR...
-p "PROMPT" 提示符
-t timeout 超时时间



上面将文件路径分别保存到变量file1、 file2中
在交互输入中包括二种状态
第一种情况:交互输入的值在于变量
当给定的变量与输入不匹配时,自左至右分别赋值,
把剩余给最后一个变量 。示例如下:,将debug message给变量b



第二种情况 :变量值大于交换输入的值,后续的变量将不会赋值。
输出则为空。示例:变量a ,b 赋值,c为空



在交互前输入相关提示信息,read可利用-p选项
echo –n 输入不换行






示例:
#!/bin/bash           #
read -p "Plz enter a username: " -t 5 username
if [ -z "$username" ]; then   #变量值为空值则赋默认值为myuser                     username="myuser"                 fi
if id $username &> /dev/null; then   #如果用户存在则输出                    echo "$username exists."                 else                     useradd $username                 fi
7) 命令引用: 引用命令的执行结果
`COMMAND`, $(COMMAND)
引用命令的执行结果;
(1) ls `which cat` which cat的结果作为ls的参数使用
(2) lines=$(wc -l /etc/fstab | cut -d' ' -f1) 变量赋值



将结果15赋给变量lines

示例:
#!/bin/bash
#
if [ -f $1 ]; then
lines=$(wc -l $1 | cut -d' ' -f1)                                       echo "$1 has $lines lines."
else
echo "$1 not exists or not a file."                                       fi
练习:写一个脚本,完成如下功能;
判断给定的两个数值,孰大孰小;
给定数值的方法:脚本参数,命令交互;

#!/bin/bash
#
read -p "Plz enter two integer: " -t 10 num1 num2
if [ -z "$num1" ]; then
echo "Plz give two integers."
exit 1
fi

if [ -z "$num2" ]; then
echo "Plz give tow integers."
exit 1
fi
if [ $num1 -ge $num2 ]; then
echo "Max: $num1, Min: $num2."
else
echo "Max: $num2, Min: $num1."
fi
8)循环语句:
内置三种循环语句:for, while, until
第一:定义
循环:将循环体代码执行0、1或多次;
进入条件:进入循环的条件;
退出条件:循环终止的条件;
第二:语法定义
A)语法结构
for VARIABLE in LIST; do
循环体
done (到此结束)
LIST:是由一个或多个空格或换行符分隔开的字符串组成;
把列表的每个字符串逐个赋值给VARIABLE表示的变量;
示例:
for username in user1 user2 user3; do
循环体
done
user1给username赋值
进入条件:列表非空; (将user1、至user3为进行条件)
退出条件:列表遍历结束;(到最后一个变量)
示例:
添加10个用户,user1-user10;
#!/bin/bash
#
for username in user1 user2 user3 user4 user5; do                         if id $username &> /dev/null; then                                  echo "$username exists."                                           else
useradd $username                                               echo "Add user $username finished."                               fi
done
B)LIST的生成方法
Part 1:(1) 整数列表
(a) {start..end}
(b) $(seq [start [[step]] end) 整数步进方式(seq是内部命令)默认从1开始
例如:seq 10 ,自动生成1-10,或者seq 10 20 自动生成10-20
seq 1 2 10 表示从1开始,到10结束,步进为2,这样输出为1,3,5,7,9奇数
seq 2 2 10 表示输出2,4,6,8,10 偶数
(2) 直接给出列表
(3) glob (文件名、通配方式)
(4) 命令生成 (命令输出为列表,以空格或换行符组成的都为列表)
示例1:数值列表
#!/bin/bash
#

for i in {1..10}; do
if id user$i &> /dev/null; then
echo "user$i exists."
else
useradd user$i
echo "Add user user$i finished."
fi
done

示例2:glob

file判断文件类型,判断/var/log目录下的所有文件类型

#!/bin/bash
#
for filename in /var/log/*; do
file $filename
done
示例:命令生成列表3 ,判断用户基本组的组名,
其中$(cut -d: -f1 /etc/passwd)为命令引用

#!/bin/bash
#
for username in $(cut -d: -f1 /etc/passwd); do
echo "$username primary group: $(id -n -g $username)."

#备注:$(id -n -g $username)表示命令结果放到此处
done
Part 2 算术运算
let命令
算术运算符 +, -, *, /, %, **
(1) $[$A+$B] 求和 $[ ]
(2) $(($A+$B)) $(( )) 与$ [ ] 结果相同
(3) let VARIABLE=$A+$B let命令需要赋值后引用,方式(1)(2)不需要赋值
示例:a=3 b=4 (赋值)
let sum=$a + $b
echo $sum



(4) VARIABLE=$(expr $A + $B) expr命令引用,引用后给变量



expr 后面需要空格
示例:求100以内所以正整数之和;

#!/bin/bash
#
declare -i sum=0     申明变量,给初始值
for i in {1..100}; do
sum=$[$sum+$i]
done
echo $sum
练习:求100以内所有偶数之和;
使用至少三种方法实现;
#!/bin/bash
#
declare -i sum=0
for i in $(seq 0 2 100); do
sum=$(($sum+$i))
done
echo "Even sum: $sum."


#!/bin/bash
#
declare -i sum=0
for i in {1..100}; do
if [ $[$i%2] -eq 0 ]; then
sum=$[$sum+$i]
fi
done
echo "Even sum: $sum."
Part3 增强型赋值:
+= 自身赋值
sum=$[$sum+$i]
let sum+=$i (help let)
-=, *=, /=, %= (除、取模)
let count=$[$count+1] --> let count+=1 --> let count++ 自动+1
let count=$[$count-1] --> let count-=1 --> let count-- 自动减1
示例:显示/etc目录下所有普通文件列表,而后统计一共有多少个文件;
#!/bin/bash
#
declare -i count=0
for file in /etc/*; do
if [ -f $file ]; then
let count++
echo "$count $file"
fi
done
echo "Total: $count files."
Part 4 测试表达式:
整数测试:-gt 大于, –lt 小于, -ge, -le, -eq, -ne
字符串测试:==, >, <, !=, –z 是否为空, -n, 是否不空
=~ 左侧字符串可以右侧给的模式匹配
注意:
(1) 字符串等时比较测试:用单括号,同时== 二侧有空格 示例: [ "$hostname" == 'localhost' ]
(2) 模式匹配测试:[[ "STRING" =~ PATTERN ]] 必须在双括号中,同时=~ 二侧需要有空格
判断左侧变量字符串与右则匹配



. 表示单个字符,需要转译符\. \.txt$ 以.txt结尾
组合测试条件:
条件间逻辑运算:
与:多个条件要同时满足;
或:多个条件满足其一即可;
非:对指定的条件取反;
表达式组合:
与:[[ CONDITION1 -a CONDITION2 ]]
或:[[ CONDITION1 -o CONDITION2 ]]
非:[ ! CONDITION ] CONDITION为表达式
命令组合:
与:COMMAND1 && COMMAND2 <-- [ EXPR1 ] && [ EXPR2 ]
或:COMMAND1 || COMMAND2
非:! COMMAND
短路操作符:&& 如果前为真后为真,如果前为假后为假
false && true = false
false && false = false
true && false = true
true && true = true
示例:如果id $username &>/dev/null有这个用户则输出用户



if COMMAND1; then
COMMAND2
fi
短路操作符:|| 如果第一个为真,都为真,(或)
true || true = true
true || false = true
false || true = true
false || false = false
示例:如果每个用户不存在,添加一个新用户



if ! COMMAND1; then
COMMAND2
fi
示例:



如果command1为真则执行command2,不执行command3
如果command1为假,则执行command3
COMMAND1 && COMMAND2 || COMMAND3
与下而if执行的结果相同(&& 的优先级高于 || )
if COMMAND1; then
COMMAND2
else
COMMAND3
fi

示例:写一个脚本实现如下功能;
获取当前主机的主机名;
如果当前主机的主机名为空,或者为localhost,则将其修改为www.magedu.com

#!/bin/bash
#
hostname=$(hostname)   #红色为主机名
if [ -z "$hostname" -o "$hostname" == "localhost" ];
then
hostname www.magedu.com
fi
练习:写一个脚本
(1) 传递两个文本文件路径给脚本;
(2) 显示两个文件中空白行数较多的文件及其空白行的个数;
(3) 显示两个文件中总行数较多的文件及其总行数;
首先定义二个文件,分别为file1,file2,路径为/tmp/51cto/mkshell/
脚本如下:用read –P 读取文件路径,四个条件分别赋值进行比较



练习:写一个脚本
(1) 提示用户输入一个字符串;
(2) 判断:
如果输入的是quit,则退出脚本;
否则,则显示其输入的字符串内容;



练习:写一个脚本,打印九九乘法表;
循环嵌套
1X1=1
1X2=2 2X2=4
1X3=3 2X3=6 3X3=9
#!/bin/bash
#
for j in {1..9}; do
for i in $(seq 1 $j); do      表示从1至j结束
echo -n -e "
${i}X${j}=$[$i*$j]\t"  -n表示不换行红色标记部分为输出字符 \t表示制表符
done
echo
done
9) 多分支的if语句:
单分支:
if CONDITION; then
if-true-分支
fi
双分支:
if CONDITION; then
if-true-分支
else
if-false-分支
fi
多分支:
if CONDITION1; then
if-CONDITION1-true-分支
elif CONDTION2; then
if-CONDITIO2-true-分支
...
else
if-ALL-false-分支 #都不满足的情况
fi
示例:通过脚本参数传递一个文件路径给脚本,判断其类型;
采用引用的方式
#!/bin/bash
#
if [ $# -lt 1 ]; then #判断是否为空
echo "Usage: $0 <path>" #为空用脚本+路径方式输入
exit 1
fi
if [ -f $1 ]; then
echo "Rgular file."
elif [ -d $1 ]; then
echo "Directory."
elif [ -h $1 ]; then
echo "Symbolic link."
elif [ -b $1 ]; then
echo "Block special."
elif [ -c $1 ]; then
echo "Charactoer special."
elif [ -S $1 ]; then
echo "Socket file."
else
echo "file not exist or unknown type."
fi
示例:脚本可接受四个参数
start: 创建文件/var/lock/subsys/SCRIPT_NAME
stop: 删除此文件
restart: 删除此文件并重新创建
status: 如果文件存在,显示为"running",否则,显示为"stopped"
basename命令:
取得路径的基名;
#!/bin/bash
#
prog=$(basename $0)   #表示引用命令的结果 $0命令获取自己的其名
lockfile="/var/lock/subsys/$prog"
#echo $lockfile
if [ $# -lt 1 ]; then     #不能为空
echo "Usage: $prog start|stop|restart|status"
exit 1
fi
if [ "$1" == "start" ]; then
if [ -f $lockfile ]; then
echo "$prog is started yet."
else
touch $lockfile && echo "Starting $prog ok..." || echo "Starting $prog failed..."
fi
elif [ "$1" == 'stop' ]; then
if [ -f $lockfile ]; then
rm -f $lockfile && echo "Stop $prog ok...." || echo "Stop $prog failed..."       else
echo "$prog is stopped yet."
fi
elif [ "$1" == 'restart' ]; then
if [ -f $lockfile ]; then
rm -f $lockfile && touch $lockfile && echo "Restarting $porg ok..."
else
touch $lockfile && echo "$prog is stopped, Starting $prog ok...."
fi
elif [ "$1" == 'status' ]; then
if [ -f $lockfile ]; then
echo "Running..."
else
echo "Stopped..."
fi
else
echo "Usage: $prog start|stop|restart|sttus"                     exit 1   代表非正常退出
fi
10)case语句
简洁版多分支if语句;
使用场景:判断某变量的值是否为多种情形中的一种时使用;

语法:
case $VARIABLE in
PATTERN1)
分支1
;;
PATTERN2)
分支2
;;
PATTERN3)
分支3
;;
...
*)
分支n
;;
esac
PATTERN可使用glob模式的通配符:
*: 任意长度的任意字符;
?: 任意单个字符;
[]: 指定范围内的任意单个字符;
a|b: 多选1;
示例:提示键入任意一个字符;判断其类型;

#!/bin/bash
#
read -p "Plz enter a character: " char
case $char in
[a-z])
echo "A character."
;;
[0-9])
echo "A digit."
;;
*)
echo "A special character."
;;
esac


示例:脚本可接受四个参数
start: 创建文件/var/lock/subsys/SCRIPT_NAME
stop: 删除此文件
restart: 删除此文件并重新创建
status: 如果文件存在,显示为"running",否则,显示为"stopped"
#!/bin/bash
#
prog=$(basename $0)
lockfile="/var/lock/subsys/$prog"
#echo $lockfile
if [ $# -lt 1 ]; then
echo "Usage: $prog start|stop|restart|status"
exit 1
fi
case $1 in
start)
if [ -f $lockfile ]; then
echo "$prog is started yet."
else
touch $lockfile && echo "Starting $prog ok..." || echo "Starting $prog failed..."
fi
;;
stop)
if [ -f $lockfile ]; then
rm -f $lockfile && echo "Stop $prog ok...." || echo "Stop $prog failed..."             else
echo "$prog is stopped yet."
fi
;;
restart)
if [ -f $lockfile ]; then
rm -f $lockfile && touch $lockfile && echo "Restarting $porg ok..."              else
touch $lockfile && echo "$prog is stopped, Starting $prog ok...."            fi
;;
status)
if [ -f $lockfile ]; then
echo "Running..."
else
echo "Stopped..."
fi
;;
*)
echo "Usage: $prog start|stop|restart|sttus"
exit 1
esac
11)流程控制:
循环语句:for, while, until

A)while循环:
while针对次数未知情况,通过控制变量进行控制
sleep 5 睡眠5秒钟
while CONDTION; do
循环体
done
进入条件:当CONDITION为“真”;
退出条件:当CONDITION为“假”;
while CONDITION; 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: $sum."
练习:分别求100以内所有奇数之和,及所有偶数之和;
奇数之和
示例:
#!/bin/bash
#
declare -i sum=0
declare -i m=1
while [ $m -le 10 ];do   #小于等于10,控制循环
if [ $[$m%2] -eq 1 ];then   #%2表示取模,为1代表奇数,0代表偶数
sum=$[$sum+$m]
fi
let m++
done
echo "oushu sum is :$sum"
#示例:打印九九乘法表
#!/bin/bash
#
declare -i i=1
declare -i j=1
while [ $j -le 9 ]; do
while [ $i -le $j ]; do                                 echo -e -n "${i}X${j}=$[$i*$j]\t"                             let i++
done
echo
let i=1
let j++
done
B)unitl循环:
until CONDITION; do
循环体
循环控制变量的修正表达式
done
进入条件:当CONDITION为“假”时
退出条件:当CONDITION为“真”时
示例:求100以内所有正整数之和

#!/bin/bash
#
declare -i sum=0
declare -i i=1
until [ $i -gt 100 ]; do
let sum+=$i
let i++
done
echo "Sum: $sum."
练习1:分别求100以内所有偶数之和,以及所有奇数之和;



练习2:实现九九乘法表;





练习3:分别使用while和until循环实现添加10个用户:user1-user10;
使用while循环:(用小于等于le进行判断)





使用until循环:(使用-gt 大于进行判断)





12)循环控制:
continue
:提前结束当前本轮循环,而直接进入下一轮;
break
:提前结束循环;(当前上一次循环)
while循环:
while CONDITION; do
.......
if CONDITION2; then
break

fi
done
while CONDITION; do
......
if CONDITION2; then
continue

fi
......
done
示例:求100以内所有偶数之和;(-le 小于等于 )
#!/bin/bash
#
declare -i sum=0
declare -i i=0
while [ $i -le 100 ]; do
let i++
if [ $[$i%2] -eq 1 ]; then   #等于1为奇数                              echo "$i is a odd."
continue  #遇到后面的代码不执行,重新进入while循环
fi
let sum+=$i
done
echo "Sum: $sum."
死循环:
while true; do (当真循环,为假时退出)
循环体
if CONDTION; then
break
fi
done
until false; do (当假循环,为真时退出)
循环体
if CONDITION; then
break
fi
done
示例:每隔3秒钟查看当前系统上是否有名为“gentoo”的用户登录;
如果某次查看gentoo登录了,则显示gentoo已经登录;
如果未登录,就显示仍然未来,并显示这是已经是第多少次查看了;
#!/bin/bash
#
username=$1
declare -i count=0
while true; do
if who | grep "^$username" &> /dev/null; then                          echo "$username is logged."
break
else
let count++
echo "$count $username is not login."
fi
sleep 3
done

#!/bin/bash
#
declare -i count=0
username=$1
if [ $# -lt 1 ]; then   #判断参数是否为空
echo "At lease one argument."
exit 1
fi
if ! id $username &> /dev/null; then
echo "No such user."
exit 2
fi
until who | grep "^$username" &> /dev/null; do (条件作为循环条件)
let count++
echo "$count $username is not login."
sleep 3
done
echo "$username is logged on."

while循环的特殊用法:
遍历文件的每一行:
while read VARIABLE; do
循环体
done < /PATH/FROM/SOME_FILE #后为重定向,提供给
VARIBLE
示例:找出UID为偶数的所有用户,显示其用户名和ID号;

#!/bin/bash
#
while read line; do
userid=$(echo $line | cut -d: -f3)
if [ $[$userid%2] -eq 0 ]; then                                 echo $line | cut -d: -f1,3
fi
done < /etc/passwd  #将/etc/passwd传给 line变量,从第一行开始操作)

for循环的特殊用法:
for ((expr1;expr2;expr3)); do
循环体
done
expr1: 定义控制变量,并初始赋值;
expr2: 循环控制条件;
进入条件:控制条件为“真”
退出条件:控制条件为“假”
expr3: 修正控制变量
示例:求100以内所有正整数之和;                   #!/bin/bash
#
declare -i sum=0
for ((i=1;i<=100;i++)); do
let sum+=$i
done
echo "Sum: $sum."


练习1:打印九九乘法表;





练习2:传递一个文本文件为参数给脚本,取出此文件的所有的偶数行给予显示,行前要显示行号;
cat –n 显示行号(包括空行) -b显示行号(不包括行号)
使用while循环语句,其中变量m用于判断行号,从1开始并计数,同时与2取模判断是否为偶数行,如果为
偶数行采用变量 m 加上行输出,/etc/fstab文件作为 readline的输入



第五: 函数:
函数即function: 功能
把一段具有独立功能代码封装在一起,并给予命名;后续用到时,可直接通过给定函数名来调用整体代码;
函数只有被调用才会执行,不调用的情况下不会执行。
函数作用:
代码重用;
模块化编程;
函数的使用方法:
先定义:编写函数代码
后调用:给出函数名,还可按需传递参数
定义方法:
(1) function f_name {
函数体
}
(2) f_name() {
函数体
}
调用函数:
f_name [argu1, argu2, ...] 参数可选
示例:创建函数countines,进行循环如果文件是普通文件
-f(判断)则显示行数(这时调用countlines函数)



函数调用$1 、$2等方法进行调用
自定义函数状态返回值:
return [#]
0: 成功
1-255:失败
注意:函数代码执行时,一旦遇到return,函数代码终止运行,函数返回;
示例:此前的服务脚本

#!/bin/bash
#
prog=$(basename $0)
lockfile="/var/lock/subsys/$prog"
#echo $lockfile
if [ $# -lt 1 ]; then
echo "Usage: $prog start|stop|restart|status"
exit 1
fi
start() {  #定义start函数
if [ -f $lockfile ]; then
echo "$prog is started yet."
else
touch $lockfile && echo "Starting $prog ok..." || echo "Starting $prog failed..."
fi                 }
stop() {      #定义stop函数
if [ -f $lockfile ]; then
rm -f $lockfile && echo "Stop $prog ok...." || echo "Stop $prog failed..."       else
echo "$prog is stopped yet."
fi                 }
restart() {    #定义restart函数
if [ -f $lockfile ]; then
rm -f $lockfile && touch $lockfile && echo "Restarting $porg ok..."               else
touch $lockfile && echo "$prog is stopped, Starting $prog ok...."           fi                 }
status() {     #定义status函数
if [ -f $lockfile ]; then
echo "Running..."
else
echo "Stopped..."
fi                 }
case $1 in
start)
start   #调用start函数
;;
stop)
stop   #调用stop函数
;;
restart)
restart   #调用restart函数
;;
status)
status   #调用status函数
;;
*)
echo "Usage: $prog start|stop|restart|sttus"
exit 1
esac


示例:判断用户的ID号的奇偶性; (函数接受参数)

#!/bin/bash
#
evenid() {   #定义函数
if [ $# -lt 1 ]; then   #判断参数个数是滞小于1,不为空                 return 1   #函数退出,后面代码不会执行                    fi

if ! id $1 &> /dev/null; then   #判断用户是否存在                    return 2
fi
userid=$(id -u $1)   #取出ID
if [ $[$userid%2] -eq 0 ]; then   #判断userid的奇偶性                   echo "$1, Even user ID."
else
echo "$1, Odd user ID."
fi                 }
以上函数定义完成
evenid root
evenid
echo $? #echo作为输出数据
evenid rooooooooooooot
echo $?
#以上都在同一个脚本当中
第六:模块化编程
功能:把脚本文件中的代码分隔为多段,放在不同的文件中
假设/root/bin/srv目录有两个文件:
(1) 函数文件 如示例start,restart、
(2) 脚本文件
为脚本使用配置文件
一个文件中只定义变量
脚本文件source此变量定义的文件
变量的作用域:
局部变量:
local VARIABLE=value
示例:



输出为



存活时间:
函数执行开始,至函数返回结束;
示例:
functins定义文件
包括Start,stop,restart,status,*等文件定义
start() { #定义start函数
if [ -f $lockfile ]; then
echo "$prog is started yet."
else
touch $lockfile && echo "Starting $prog ok..." || echo "Starting $prog failed..."
fi
}
如下中. 脚本文件source此变量定义



运行hisrv.sh文件,要求在一个目录下运行:调用./hisrv.sh start



示例2:
在一个同一目录创建username.conf文件内容如下:本文件中只定义变量



在脚本中source此定义的文件,只需要修改username.conf文件变量
脚本useradd.sh
如果文件可读,利用. source username.conf



作业:上述关于bash编辑所有语法知识点和总结,要求图文并茂

Part 2:作业部分
作业5:写一个脚本:如果某路径不存在,则将其创建为目录;
否则显示其存在,并显示内容类型



作业6:
写一个脚本,完成如下功能;判断给定的两个数值,孰大孰小;给定数值的方法:
脚本参数,命令交互;(使用read,依然如此简单)



作业7:求100以内所有奇数之和
方法1: while循环



方法2:until



方法3:



作业8:
写一个脚本实现如下功能:
(1) 传递两个文本文件路径给脚本;
(2) 显示两个文件中空白行数较多的文件及其空白行的个数;
(3) 显示两个文件中总行数较多的文件及其总行数;
首先定义二个文件,分别为file1,file2,路径为/tmp/51cto/mkshell/
脚本如下:用read –P 读取文件路径,四个条件分别赋值进行比较




作业9:
写一个脚本
(1) 提示用户输入一个字符串;
(2) 判断:
如果输入的是quit,则退出脚本;
否则,则显示其输入的字符串内容;



作业:10:写一个脚本,打印2^n表;n等于一个用户输入的值;
利用sum作为输出,输入数值作为for循环控制





作业11:写一个脚本,写这么几个函数:函数1、实现给定的两个数值的之和;函数2、
取给定两个数值的最大公约数;函数3、取给定两个数值的最小公倍数;关于函数的选定、
两个数值的大小都将通过交互式输入来提供。
gcd最大公约数    gbs最小公倍数=a*b/最大公约数
第一:创建脚本文件
maxgcd用于计算最小公倍数时,调用gcd函数保存的变量
三个函数分为按照1,2,3进行数字选择



第二:功能函数:
最大公约数利用until循环进行判断,首先判断是否第一个数字大于
第二个数字,当第一个数字小于第二个数字时进行数字调换。
然后利用until判断,当余数为0时退出循环,同时进行数字交换。
计算完成将最大公约数赋值给maxgcd变量。
当调用最大倍数时,调用gcd函数,取得maxgcd值。变将最大公
公约数的输出到/dev/null中。同时根据最大公约数与最大公倍数的公式
进行计算。


内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: