一、shell编程(四)
1、循环特殊用法
while 循环的特殊用法(遍历文件的每一行):
while read line; do 循环体 done < /PATH/FROM/SOMEFILE 依次读取/PATH/FROM/SOMEFILE文件中的每一行,且将行赋值给变量line
双小括号方法,即((…))格式,也可以用于算术运算
双小括号方法也可以使bash Shell 实现C语言风格的变量操作 #I=10 #((I++))
for 循环的特殊格式:
for ((控制变量初始化;条件判断表达式;控制变量的修正表达式))do 循环体done控制变量初始化:仅在运行到循环代码段时执行一次 控制变量的修正表达式:每轮循环结束会先进行控制变量修正运算,而后再做条件判断
select 循环与菜单
select: select NAME [in WORDS ... ;] do COMMANDS; done select variable in list do 循环体命令 doneselect 循环主要用于创建菜单,按数字顺序排列的示菜单项将显示在标准错误上,并显示PS3提示符,等待用户输入 PS3="would you like ?"用户输入菜单列表中的某个数字,执行相应的命令 用户输入被保存在内置变量 REPLY 中。 注意:select循环为死循环 [root@6 cd]# select name in a b c d;do echo "you choose is $name"; done 1) a 2) b 3) c 4) d #? 3 you choose is c #? 2 you choose is b #? [root@6 bin]#PS3="would you like ?" [root@6 bin]# select name in a b c d;do echo "you choose is $name"; done 1) a 2) b 3) c 4) d would you like ?2 you choose is b
select与case
select 用是个无限循环,因此要记住用 break 命令退用出循环,或用 exit 按 命令终止脚本。也可以按 ctrl+c退出循环。
break #和continue #;
break #:退出#层循环continue #:跳过#次循环 select和经常和case联合使用 与 for循环类似,可以省略 in list,此时使用位置参量 #! /bin/bash PS3="would you like ?"select choose in a b c d;do case $choose in a) echo "THIS IS A PART." ;; b) echo "THIS IS B PART." ;; c) echo "THIS IS C PART." ;; d) echo "THIS IS D PART." ;; *) break ;; esacdone
2、函数介绍
函数function是由若干条shell命令组成的语句块,实现代码重用和模块化编程。 优先级:alias》函数》内部命令》外部命令 它与shell程序形式上是相似的,不同的是它不是一个单独的进程,不能独立运行,而是shell 程序的一部分。 函数和shell程序比较相似,区别在于:Shell 程序在子Shell中运行 而Shell函数在当前Shell中运行。因此在当前Shell 中,函数可以对shell 中变量进行修改
定义函数
函数由两部分组成:函数名和函数体。 语法一: function f_name { ... 函数体... } 语法二: function f_name() { ... 函数体... } 语法三: f_name (){ ... 函数体... }
函数使用
函数的定义和使用: 可在交互式环境下定义函数 可将函数放在脚本文件中作为它的一部分 可放在只包含函数的单独文件中 调用:函数只有被调用才会执行; 调用:给定函数名 函数名出现的地方,会被自动替换为函数代码 函数的生命周期:被调用时创建,返回时终止
函数返回值
函数有两种返回值: 函数的执行结果返回值: (1)使用echo 或printf 命令进行输出 (2) 函数体中调用命令的输出结果 函数的退出状态码: (1)默认取决于函数中执行的最后一条命令的退出状态码 (2)自定义退出状态码, 其格式为: return 从函数中返回,用最后状态命令决定返回值 return 0 无错误返回。 return 1-255 有错误 返回
交互式环境下定义和使用函数
示例: $dir() { > ls -l > } 定义该函数后,若在$ 后面键入dir ,其显示结果同ls -l的作用相同。 $dir该dir函数将一直保留到用户从系统退出,或执行了如下所示的unset 命令: $ unset dir
在脚本中定义及使用函数
函数在使用前必须定义,因此应将函数定义放在脚本开始部分,直至shell 首次发现它后才能使用 调用函数仅使用其函数名即可。 示例: $cat func1 #!/bin/bash # func1 hello() { echo "Hello there today's date is `date +%F`" } echo "now going to the function hello" hello echo "back from the function"
使用函数文件
可以将经常使用的函数存入函数文件,然后将函数文件载入shell。 文件名可任意选取,但最好与相关任务有某种联系。例如:functions.main 一旦函数文件载入shell,就可以在命令行或脚本中调用函数。可以使用set 命令查看所有定义的函数,其输出列表包括已经载入shell的所有函数。 若要改动函数,首先用unset 命令从shell中删除函数。改动完毕后,再重新载入此文件。
创建函数文件
函数文件示例: $cat functions.main #!/bin/bash #functions.main findit() { if [ $# -lt 1 ] ; then echo "Usage:findit file" return 1 fi find / -name $1 –print }
载入函数
函数文件已创建好后,要将它载入shell 定位 函数文件 并载入shell 的格式: . filename 或 source filename 注意:此即< 点> < 空格> < 文件名>这里 的文件名要带正确路径 示例:上例中的函数,可使用 如下命令: $ . functions.main
检查载入函数
使用set命令检查函数是否已载入。set 命令将在shell中显示所有的载入函数 。 示例: $set findit=( ) { if [ $# -lt 1 ]; then echo "usage :findit file"; return 1 fi find / -name $1 -print } …
执行shell 函数
要执行函数,简单地键入函数名即可 : 示例: $findit groups /usr/bin/groups /usr/local/backups/groups.bak
删除shell函数
现在对函数做一些改动。首先删除函数,使其对shell 不可用。使用unset 命令完成此 功能. 命令格式为:unset function_name 实例:$unset findit 再键入set 命令,函数将不再 显示
函数参数
函数可以接受参数: 传递参数给函数:调用函数时,在函数名后面以空白分隔给定参数列表即可;例如“testfunc arg1 arg2 ...” 在函数体中当中,可使用$1, $2, ...调用这些参数;还可以使用$@, $*, $# 等特殊变量
函数变量
变量作用域: 环境变量:当前shell和子shell 有效 本地变量:只在当前shell进程有效,为执行脚本会启动专用子shell进程;因此,本地变量的作用范围是当前shell脚本程序文件,包括脚本中的函数。 局部变量:函数的生命周期;函数结束时变量被自动 销毁 注意:如果函数中有局部变量,如果其名称同本地变量, 使用局部变量。 在函数中定义局部变量的方法 local NAME=VALUE
函数递归实例
函数递归: 函数直接或间接调用自身 注意递归层数 递归实例: 阶乘是基斯顿·于 卡曼于 1808 年发明的运算符号,是数学术语 一个正整数的阶乘(factorial)是所有小于及等于该数的正整数的积,并且有0 的阶乘为1 。自然数n 的阶乘写作n!。 。 n!=1 ×2 ×3 ×... ×n。 。 阶乘亦可以递归方式定义:0!=1 ,n!=(n-1)! ×n。 。 n!=n(n-1)(n-2)...1 n(n-1)! = n(n-1)(n-2)!
函数 递归示例
示例: fact.sh#!/bin/bash#fact() { if [ $1 -eq 0 -o $1 -eq 1 ]; thenecho 1 elseecho $[$1*$(fact $[$1-1])]fi} fact $1
二、软件包管理(二)
包查询
rpm {-q|--query} [select-options] [query-options] [select-options] -a: 所有包-f: 查看指定的文件由哪个程序包安装生成[root@6 yum.repos.d]# rpm -qf /bin/rpmrpm-4.8.0-55.el6.x86_64 -p rpmfile(包名):针对尚未安装的程序包文件做查询操作; [root@6 cd]# rpm -qp /misc/cd/Packages/tree-1.5.3-3.el6.x86_64.rpm tree-1.5.3-3.el6.x86_64 --whatprovides CAPABILITY :查询指定的 CAPABILITY由哪个包所提供 [root@6 cd]# rpm -q --whatprovides rpm rpm-4.8.0-55.el6.x86_64 --whatrequires CAPABILITY :查询指定的 CAPABILITY 被哪个包所依赖 [root@6 cd]# rpm -q --whatrequires rpm rpm-libs-4.8.0-55.el6.x86_64 man-1.6f-32.el6.x86_64 rpm-python-4.8.0-55.el6.x86_64 yum-3.2.29-73.el6.centos.noarch policycoreutils-2.0.83-29.el6.x86_64 python-meh-0.12.1-3.el6.noarch rpm2cpio 包文件|cpio –itv 预览包内文件 rpm2cpio 包文件|cpio –id “*.conf” ” 释放包内文件 [root@6 cd]# rpm2cpio /misc/cd/Packages/rpm-4.8.0-55.el6.x86_64.rpm |cpio -id /bin/rpm ##恢复删除的文件 [query-options] --changelog :查询rpm包的changelog-c: 查询程序的配置文件-d: 查询程序的文档-i: information-l: 查看指定的程序包安装后生成的所有文件;--scripts :程序包自带的脚本片断-R:查询指定的程序包所依赖的CAPABILITY; --provides:列出指定程序包所提供的CAPABILITY; 查询用法: -qi PACKAGE, -qf FILE, -qc PACKAGE, -ql PACKAGE, -qd PACKAGE -qpi PACKAGE_FILE, -qpl PACKAGE_FILE,... -qa 卸载: rpm {-e|--erase} [--allmatches] [--nodeps] [--noscripts] [--notriggers] [--test] PACKAGE_NAME ... rpm {-V|--verify} [select-options] [verify-options] S file Size differs M Mode differs (includes permissions and file type) 5 digest (formerly MD5 sum) differs D Device major/minor number mismatch L readLink(2) path mismatch U User ownership differs G Group ownership differs T mTime differs P capabilities differ
包校验
包来源合法性验正及完整性验正: 完整性验正:SHA256 来源合法性验正:RSA 公钥加密: 对称加密:加密、解密使用同一密钥; 非对称加密:密钥是成对儿的 public key: 公钥,公开所有人 secret key: 私钥, 不能公开 导入所需要公钥: rpm -K|checksig rpmfile 检查包的完整性和签名 [root@6 cd]# rpm -K /misc/cd/Packages/tree-1.5.3-3.el6.x86_64.rpm /misc/cd/Packages/tree-1.5.3-3.el6.x86_64.rpm: rsa sha1 (md5) pgp md5 OK rpm --import /etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7 ##导入key文件 CentOS 7 发行版光盘提供: RPM-GPG-KEY-CentOS-7 rpm -qa gpg-pubkey*
rpm数据库
数据库重建: /var/lib/rpmrpm {--initdb|--rebuilddb} initdb: 初始化 如果事先不存在数据库,则新建之 否则,不执行任何操作 rebuilddb :重建 无论当前存在与否,直接重新创建数据库
yum
CentOS: yum, dnfYUM: Yellowdog Update Modifier,rpm的前端程序,用来解决软件包相关依赖性,可以在多个库之间定位软件包,up2date 的替代工具 yum repository: yum repo ,存储了众多rpm 包,以及包的相关的元数据文件(放置于特定目录repodata 下) 文件服务器: ftp:// http:// file:///
yum 配置文件
yum 客户端配置文件: /etc/yum.conf :为所有仓库提供公共配置 /etc/yum.repos.d/*.repo :为仓库的指向提供配置 仓库指向的定义: [repositoryID] name=Some name for this repository baseurl=url://path/to/repository/ enabled={1|0} gpgcheck={1|0} gpgkey=URL enablegroups={1|0} failovermethod={roundrobin|priority} 默认为:roundrobin ,意为随机挑选; cost= 默认为1000repo 文件范例 /etc/yum.repo.d/ [base] name=centos 7 baseurl=http://10.1.0.1/cobbler/ks_mirror/7/ gpgcheck=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentosOS-7 enabled=1
教学环境yum源
教室里的yum源:http://172.16.0.1/cobbler/ks_mirror/CentOS-X-x86_64/CentOS epel:http://172.16.0.1/fedora-epel/7/x86_64/yum 命令的用法: yum [options] [command] [package ...]
yum-config-manager
生成172.16.0.1_cobbler_ks_mirror_CentOS-X-x86_64_.repo yum-config-manager --add-repo=http://172.16.0.1/cobbler/ks_mirror/CentOS-X -x86_64/ yum-config-manager --disable “ 仓库名" 禁用仓库yum-config-manager --enable “ 仓库名” 启用仓库
yum
显示仓库列表: repolist [all|enabled|disabled]显示程序包: list # yum list [all | glob_exp1] [glob_exp2] [...] # yum list {available|installed|updates} [glob_exp1] [...]安装程序包: install package1 [package2] [...] reinstall package1 [package2] [...] (重新安装) 升级程序包: update [package1] [package2] [...] downgrade package1 [package2] [...] ( 降级) 检查可用升级: check-update 卸载程序包: remove | erase package1 [package2] [...]查看程序包information: info [...]查看指定的特性( 可以是某文件) 是由哪个程序包所提供: provides | whatprovides feature1 [feature2] [...]清理本地缓存: clean [ packages | metadata | expire-cache |rpmdb | plugins | all ]构建缓存: makecache 搜索:search string1 [string2] [...] 以指定的关键字搜索程序包名及summary 信息 查看指定包所依赖的capabilities: deplist package1 [package2] [...]查看yum事务历史: history [info|list|packages-list|packages-info| summary|addon-info|redo|undo| rollback|new|sync|stats] yum history yum history info 6 yum history undo 6 日志:/var/log/yum.log
积累应用
1 、写 一个服务脚本/root/bin/testsrv.sh ,完成如下要求
(1) 脚本可接受参数:start, stop, restart, status
(2) 如果参数非此四者之一,提示使用格式后报错退出
(3) 如是start:则创建/var/lock/subsys/ SCRIPT_NAME , 并显示“启动成功”考虑:如果事先已经启动过一次,该如何处理?
(4) 如是stop:则删除/var/lock/subsys/ SCRIPT_NAME , 并显示“停止完成”考虑:如果事先已然停止过了,该如何处理?
(5) 如是restart ,则先stop, 再start考虑:如果本来没有start ,如何处理?
(6) 如是status, 则如果/var/lock/subsys/ SCRIPT_NAME 文件存在,则显示“ SCRIPT_NAME is running…”如果/var/lock/subsys/ SCRIPT_NAME 文件不存在,则显示“ SCRIPT_NAMEis stopped…”其中: SCRIPT_NAME 为当前脚 本名
###函数 #! /bin/bash servername=SCRIPT_NAME START () { touch /var/lock/subsys/$servername echo "$servername已启动." } STOP() { rm -f /var/lock/subsys/$servername echo "$servername已停止." }
###程序 #! /bin/bash #author:lvasu #description: #version:0.1 #date: source agrement PS3="请选择参数:" servername=SCRIPT_NAME file=/var/lock/subsys/ $servername select agre in start stop restart status; do case $agre in start) if [ -f $file ];then echo "$servername已开启,不需要启动." else START fi ;; stop) if [ -f $file ];then STOP else echo "$servername未开启,不需要关闭." fi ;; status) if [ -f $file ];then echo "$servername is running...." else echo "$servername is stopped..." fi ;; restart) if [ -f $file ];then echo "$servername已开启,重启中." STOP &> /dev/null START else echo "$servername 未启动,启动中." START fi ;; *) echo "你输入的不合法." break ;; esac done
###执行效果 [root@6 bin]# ./testsrv.sh 1) start 2) stop 3) restart 4) status 请选择参数:1 SCRIPT_NAME已启动. 请选择参数:2 SCRIPT_NAME已停止. 请选择参数:3 SCRIPT_NAME 未启动,启动中. SCRIPT_NAME已启动. 请选择参数:4 SCRIPT_NAME is running....
2 、编写一个脚本/root/bin/copycmd.sh
(1) 提示用户输入一个可执行命令名称;
(2) 获取此命令所依赖到的所有库文件列表
(3) 复制命令至某目标目录( 例如/mnt/sysroot) 下的对应路径下;
如:/bin/bash ==> /mnt/sysroot/bin/bash
/usr/bin/passwd ==> /mnt/sysroot/usr/bin/passwd
(4) 复制此命令依赖到的所有库文件至目标目录下的对应路径下:
如:/lib64/ld-linux-x86-64.so.2 ==> /mnt/sysroot/lib64/ld-
linux-x86-64.so.2
(5)每次复制完成一个命令后,不要退出,而是提示用户键入新的要复制的命
令,并重复完成上述功能;直到用户输入quit 退出
###程序 #! /bin/bash #author:lvasu #description: #version:0.1 #date: while true;do read -p "请输入一个可执行的命令" cmd addr=/mnt/sysroot case $cmd in quit) exit ;; *) type $cmd &> /dev/null if [ $? -eq 0 ];then which $cmd &> /dev/null if [ $? -eq 0 ];then path=$(which $cmd | sed -rn "/\/.*\/$cmd/p") else path=/bin/bash fi else echo "请输入正确的命令." continue fi echo "复制命令的路径:" echo $path echo '==============================' files=$(ldd $path| grep -o '/.*.so.[1-9]') echo "$path的库文件:" echo "$files" | tee -a /testdir/file echo '==============================' line=$(echo "$files" |wc -l) commen1=$(echo $path | sed -nr 's@(^/.*/)[^/]+/?$@\1@p') mkdir -p $addr$commen1 &> /dev/null cp -a $path $addr$path &> /dev/null echo "$addr$path复制成功." echo '==============================' while read n;do commen2=$(echo $n|sed -nr 's@(^/.*/)[^/]+/?$@\1@p') mkdir -p $addr$commen2 &> /dev/null cp -a $n $addr$commen2 &> /dev/null echo "$addr$n复制成功." done < /testdir/file rm -f /testdir/file esac done
###执行效果 [root@6 bin]# ./copycmd.sh 请输入一个可执行的命令cd 复制命令的路径: /bin/bash ============================== /bin/bash的库文件: /lib64/libtinfo.so.5 /lib64/libdl.so.2 /lib64/libc.so.6 /lib64/ld-linux-x86-64.so.2 ============================== /mnt/sysroot/bin/bash复制成功. ============================== /mnt/sysroot/lib64/libtinfo.so.5复制成功. /mnt/sysroot/lib64/libdl.so.2复制成功. /mnt/sysroot/lib64/libc.so.6复制成功. /mnt/sysroot/lib64/ld-linux-x86-64.so.2复制成功. 请输入一个可执行的命令ip 复制命令的路径: /sbin/ip ============================== /sbin/ip的库文件: /lib64/libresolv.so.2 /lib64/libdl.so.2 /lib64/libc.so.6 /lib64/ld-linux-x86-64.so.2 ============================== /mnt/sysroot/sbin/ip复制成功. ============================== /mnt/sysroot/lib64/libresolv.so.2复制成功. /mnt/sysroot/lib64/libdl.so.2复制成功. /mnt/sysroot/lib64/libc.so.6复制成功. /mnt/sysroot/lib64/ld-linux-x86-64.so.2复制成功.
3 、斐波那契数列又称黄金分割数列,因数学家列昂纳多·斐波那契以兔子
繁殖为例子而引入,故又称为“兔子数列”,指的是这样一个数列:0 、1 、1 、2 、3 、5 、8 、13 、21 、34 、……,斐波纳契数列以如下被以递归的
方法定义:F (0 )=0 ,F (1 )=1 ,F (n )=F(n-1)+F(n-2) (n≥2) )
写一个函数,求n 阶斐波那契数列
###函数 tuzi() { if [ $1 -eq 0 ];then echo 0 elif [ $1 -eq 1 ];then echo 1 else echo $[$(tuzi $[$1-1])+$(tuzi $[$1-2])] fi } tuzi2() { for((i=0;i<=$1;i++)) if [ $i -eq 0 ];then echo 0 elif [ $i -eq 1 ];then echo 1 else echo $[$(tuzi $[$i-1])+$(tuzi $[$i-2])] fi done }
###程序 #! /bin/bash #author:lvasu #description: #version:0.1 #date: source agrement read -p "请输入斐波那契数列阶数:" n tuzi $n echo '===================' tuzi2 $n
###执行效果 [root@6 bin]# ./feibo.sh 请输入斐波那契数列阶数:10 55 =================== 0 1 1 2 3 5 8 13 21 34 55
原创文章,作者:lvasu,如若转载,请注明出处:http://www.178linux.com/38903