shell编程:
编译器,解释器
编程语言:机器语言、汇编语言、高级语言
静态语言:编译语言:编译语言:强型(变量)提前转换为可执行格式C、C 、JAVA、C#
动态语言:解释语言,on the fly弱类型边解释边执行PHP、SHELL、Python、Perl、lua
面向过程:shell,C面向对象:JAVA,Python,Perl,C
变量:内存空间,命名
内存:编址存储单元
进程:
变量类型:事件确定数据的存储格式和长度字符数值整型浮点型
逻辑:1 1>2逻辑操作:与,或,非,异或异1:真0:假
与:1 & 0 = 00 & 1 = 00 & 0 = 01 & 1 = 1
或:
非:!真=假!假=真
异或:相同为1,不同为0
短路逻辑操作:和:只要一个是假的,结果就必须是假的或者:只要一个是真的,结果就必须是真的
整型:8bit:2560-255,溢出
shell:弱编程语言
强:变量在使用前必须事先声明,甚至需要初始化;弱:用时声明变量,甚至不区分类型
显式:11 c=
变量赋值:VAR_NAME=VALUE
bash变量类型:环境变量本地变量(局部变量)位置变量特殊变量
本地变量:set VARNAME=VALUE:作用域整个bash进程
局部变量:local VARNAME=VALUE:作用域是当前代码段
环境变量:当前作用域shell过程及其子过程export VARNAME=VALUEVARNAME=VALUEexport VARNAME"导出"
位置变量:$1,$2,...
特殊变量:$?:上一个命令的执行状态返回值:
程序执行可能有两种返回值:程序执行结果程序状态返回代码(0-255)0:正确执行1-255:错误执行,预留1、2、127系统
输出重定向:
2>2>>&>
撤销变量:unset VARNAME
查看当前shell中变量:set
查看当前shell环境变量:printenvenvexport
export PATH=$PATH:/usr/local/apache/bin
脚本:根据实际需要,结合命令流程控制机制实现的源程序堆砌
shebang:魔数#! /bin/bash
注释行,不执行
/dev/null:软件设备,bit bucket,数据黑洞
脚本执行时会启动一个子shell进程:在命令行中启动的脚本将继承当前shell环境变量系统自动执行的脚本(非命令行启动)需要自我定义
引用变量:${VARNANE},括号有时可以省略
编程能力:脚本编程
练习:写脚本,完成以下任务1.添加5个用户,user1,...,user52、每个用户的密码同用户名,而且要去,添加密码完成后不显示passwd命令执行结果信息3.每个用户添加后,应显示某个用户已成功添加
练习:写脚本,完成以下任务1.用变量保存用户名;2.删除此变量中的用户,并删除其家庭目录;3、显示"用户删除完成"类的信息
条件判断:若用户不存在添加用户,成功添加密码并显示否则显示已经存在,无需添加
bash如何实现条件判断条件测试类型:整数测试字符测试文件测试
条件测试的表达式:[ expression ] [[ expression ]]test expression
整数比较:-eq:测试整个整数是否相等$A -eq $B -ne:测试两个整数是否不等:不等,为真:相等,为假-gt:测试一个数是否大于另一个数:大于,是真的,否则是假的-lt:测试一个数是否小于另一个数:小于,是真的,否则是假的-ge:大于或等于-le:小于或等于
命令间的逻辑关系:逻辑与:&&第一个条件是假的,第二个条件不需要判断,最终结果已经存在;第一个条件是真的,必须判断第二个条件逻辑或:||
如果用户user如果6不存在,则添加用户user6! id user6 && useradd user6id user6 || useradd user6
如果/etc/inittab如果文件行数大于100,则显示大文件:[ wc -l /etc/inittab | cut -d' ' -f1
-gt 100 ] && echo "Large file"
变量名称只能包含字母、数字和下划线,不能从数字开始不应与系统中现有的环境变量重名见名知义最好
如果用户存在,则显示用户存在;否则,添加此用户id user1 && echo "user1 exists" || useradd user1
如果用户不存在,则添加;否则,它已经存在! id user1 && useradd user1 || echo "user exists"
如果用户不存在,添加并给出密码;否则,显示它已经存在! id user1 && useradd user1 && echo "user1" | passwd --stdin user1 || echo "user1 exists"
练习,写一个脚本,完成以下要求:添加三个用户user1,user2,user3:但首先判断用户是否存在,然后添加2.添加后,显示添加了几个用户。当然,它不能包括事先存在但未添加的用户3.最后,显示当前系统中有多少用户
练习,写一个脚本,完成以下要求:给定用户:如果其UID为0,显示为管理员,否则显示为普通用户;
#! /bin/bashNAME=user1USERID= id -u $NAME
[ $USERID -eq 0 ] && echo "admin" || echo "common user"
#! /bin/bashNAME=user1USERID=id -u $NAME
if $USERID -eq 0 ; thenecho "admin"elseecho "common user"fi
控制结构:
单分支if语句if 判断条件; thenstatement1statement2...fi
双分支的if语句:if 判断条件; thenstatement1statement2...elsestatement3statement4...fi
多分支的if语句:if 判断条件1; thenstatement1...elif 判断条件2; thenstatement2...elif 判断条件3; thenstatement3...elsestatement4...fi
#! /bin/bashNAME=user1if id $NAME &> /dev/null(这意味着执行命令的状态,即执行成功或失败); thenecho "$NAME exists."elseuseradd $NAMEecho "$NAME" | passwd --stdin $NAME &> /dev/nullecho "Add $NAME finished."fi
练习:写脚本判断当前系统中是否有默认用户shell为bash,如果是这样示有多少这样的用户:否则,显示没有这样的用户#! /bin/bashgrep "bash$" /etc/passwd &> /dev/nullRETVAL=$?if [ $RETVAL -eq 0 ]; thenUSERS=grep "bash$" /etc/passwd | wc -l
echo "the shells of $USERS users is bash."elseecho "no such user"fi
练习:写脚本给定文件,如/etc/inittab判断本文件中是否有空白行:若有,则显示其空白行数;否则,显示没有空白行
练习:写脚本给定用户,判断用户uid与gid是否一样假如是这样,就显示一下户为"good guy":否则,就显示此用户为"bad guy".#! /bin/bashUSERNAME=user1USERID=id -u $USERNAME
GROUPID=id -g $USERNAME
if [ $USERID -eq $GRUPID ]; thenecho "GOOD guy"elseecho "Bad guy"fi
进一步要求:不使用id命令获得其id号:
练习:写一个脚本判定命令历史中历史命令的总条目是否大于1000:如果大于,则显示"some command will gone.",否则显示ok。
shell中如何进行算术运算:1、let算术运算表达式let C=$A+$Becho $C2、$[算术运算表达式]C=$[$A+$B]3、$((算术运算表达式))C=$(($A+$B))4、expr算术运算表达式,表达式中各操作数及运算符之间要有空格,而且要使用命令引用C=expr $A + $B
练习:写一个脚本给定一个用户,获取其密码警告期限:而后判断用户密码使用期限是否已经小于警告期限提示:计算方法,最长使用期限减去已经使用的天数即为剩余使用期限如果小于,则显示"warning";否则,就显示"ok"
#! /bin/bashW=grep "student" /etc/shadow | cut -d: -f6
S=date +%s
T=expr $S/86400
L=grep "^student" /etc/shadow | cut -d: -f5
N=grep "^student" /etc/shadow | cut -d: -f3
SY=$[$L-$[$T-$N]]if [ $SY -lt $W ]; thenelse 'Warning'elseelse 'OK'fi
圆整:丢弃小数点后的所有内容
测试方法:[ expression ] [[ expression ]]test expression
bash中常用的条件测试有三种:整数测试:-gt-le-ne-eq-ge-lt
INT1=63INT2=77[ $INT1 -eq $INT2 ][[ $INT1 -eq $INT2 ]]test $INT1 -eq $INT2
if grep "^$USERNAME\>" /etc/passwd; then
文件测试:-e FILE:测试文件是否存在-f FILE:测试文件是否为普通文件-d FILE:测试指定路径是否为目录-r FILE:测试当前用户对指定文件是否有读取权限-w FILE:测试当前用户对指定文件是否有写权限-x
[ -e /etc/inittab ][ -x /etc/rc.d/rc.sysinit ]
练习:写一个脚本给定一个文件:如果是一个普通文件,就显示之如果是一个目录,亦显示之否则,此为无法识别之文件#! /bin/bashFILE=/etc/rc.d/rc.sysinitif [ ! -e $FILE ]; thenecho "No such file."exit 6fi
if [ -f $FILE ]; thenecho "Common file"elif [ -d $FILE ]; thenecho "Directory"elseecho "Unknown"fi
测试脚本是否有语法错误:bash -n 脚本bash -x 脚本:单步执行
定义脚本退出状态码
exit:退出脚本exit #如果脚本没有明确定义退出状态码,那么,最后执行的一条命令的退出码即为脚本的退出状态码
bash变量的类型:本地变量(局部变量)环境变量位置变量:$1,$2,...shift特殊变量:$?$#:参数的个数$*:参数列表$@:参数列表
练习:写一个脚本能接受一个参数(文件路径)判定:此参数如果是一个存在的文件,就显示"ok";否则vim filetest3.sh#! /bin/bashif [ $# -lt 1 ]; thenecho "Usage: ./filetest3.sh ARG1 [ARG2]..."exit 7fi
if [ -e $1 ]; thenecho okelseecho "No such file"fi
bash filetest3.sh /etc/fstab
练习:写一个脚本给脚本传递两个参数(整数):显示此两者之和,之积#! /bin/bashif [ $# -lt 2 ]; thenecho "Usage: cacl.sh ARG1 ARG2"exitfiecho "The sum is:$[$1+$2]"echo "The prod is:$[$1*$2]"
练习:传递一个用户名参数给脚本,判断此用户的用户名跟基本组的组名是否一致,并将结果显示出来#! /bin/bashif ! id $1 &> /dev/null; thenecho "No such user."exit 10fi
if [ id -n -u $1
== id -n -g $1
]; thenecho "yiyang"elseecho "bu yiyang"fi
字符测试:==:测试是否相等,相等为真,不等为假!=:测试不等,不等为真,相等为假
<-n string:测试指定字符串是否为空,空则真,不空为假-z string:测试指定字符串是否不空,不空为真,空则假
练习:写一个脚本传递一个参数(单字符就行)给脚本,如果参数为q,就退出脚本,否则,就显示用户的参数
练习:写一个脚本传递一个参数(单字符就行)给脚本,如参数为q,Q,quit或者Quit,就退出脚本;否则,显示用户的参数#! /bin/bashif [ $1 = 'q' ]; thenecho "quitting..."exit 1elif [ $1 = 'Q' ]; thenecho "quitting..."exit 2elif [ $1 = 'quit' ]; thenecho "quitting..."exit 3elif [ $1 = 'Quit' ]; thenecho "quitting..."exit 4elseecho $1fi
练习:传递三个参数给脚本,第一个为整数,第二个为算术运算符,第三个为整数,将计算结果显示出来,要去保留两位精度。形如:./cacl.sh 5 / 2echo "scale=2;111/22;" | bcbc <<< "scale=2;111/22"
练习:传递3个参数给脚本,参数均为用户名,将此些用户账号信息提取出来后放置于/tmp/testusers.txt文件中,并要求每一行行首有行号
写一个脚本:判断当前主机的CPU生产商,其信息在/proc/cpuinfo文件中vendor id 一行中如果其生产商为AuthnticAMD,就显示其为AMD公司如果其生产商为GenuineIntel,就显示其为Intel公司否则,就说其非主流公司
写一个脚本:给脚本传递三个整数,判断其中的最大数和最小数,并显示出来#! /bin/bashMAX=$1MIN=$1[ $2 -gt $MAX ] && MAX=$2[ $3 -gt $MAX ] && MAX=$3echo "$MAX"[ $2 -lt $MIN ] && MIN=$2[ $3 -lt $MIN ] && MIN=$3echo "$MIN"
#! /bin/basha=1MAX=0MIN=$3while [ $a -le 3 ]do[ $1 -gt $MAX ] && MAX=$1[ $1 -lt $MIN ] && MIN=$1shift 1a=$(($a+1))doneecho $MAXecho $MIN
循环:进入条件,退出条件forwhileuntil
for 变量 in 列表; do循环体done
for i in 1 2 3 4 5 6 7 8 9 10; do加法运算done
遍历完成之后,退出:
如何生成列表:{1..100}seq [起始数 [步进长度]] 结束数
declare -i SUM=0
#! /bin/bashdeclare -i SUM=0for i in {1..100}; d0let SUM=$[SUM+$i]doneecho "the sum is:$SUM."
写一个脚本:1.设定变量FILE的值为/etc/passwd2.依次向/etc/passwd中的每个用户问好,并显示对方的shell,形如:hello,root,your shell: /bin/bash3.统计一共多少个用户for i in seq 1 $LINES
; do echo "Hello,head -n $I /etc/passwd | tail -1 | cut -d: -f1
"; done
只向默认shell为bash的用户问声好
写一个脚本:1.添加10个用户user1到user10,密码同用户名:但要求只有用户不存在的情况下才能添加#! /bin/bashfor i in user{1..10}; doif id $i &> /dev/null; thenecho "$i exists."elseuseradd $iecho $i | passwd --stdin $i &> /dev/nullecho "add user $i finished."fidone
扩展:接受一个参数:add:添加用户user1..user10del:删除用户user1..user10其它:退出#! /bin/bashif [ $# -lt 1 ]; thenecho "Usage: adminusers ARG"exit 7fi
if [ $1 == '--add' ]; thenfor i in {1..10}; doif id user$i &> /dev/null; thenecho "user$i exists."elseuseradd user$iecho user$i | passwd --stdin user$i &> /dev/nullecho "Add user$i finished."fidoneelif [ $1 == '--del' ]; thenfor i in {1..10}; doif id user$i &> /dev/null; thenuserdel -r user$iecho "user$i exists."elseecho "No user$i." fidoneelseecho "Unknown ARG"exit 8fi
#! /bin/bashif [ $1 == '--add' ]; thenfor i in echo $2 | sed 's/,/ /g'
; doif id $i &> /dev/null; thenecho "$i exists."elseuseradd $iecho $i | passwd --stdin $i &> /dev/nullecho "add $i finished."fidone elif [ $1 == '--del' ]; thenfor i in echo $2 | sed 's/,/ /g'
; doif id $i &> /dev/null; thenuserdel -r $iecho "delete $i finished"elseecho "$i not exist"fidoneelif [ $1 == '--help' ]; thenecho "Usage:adminuser2.sh --add user1,user2... | --del user1,user2...| --help"elseecho "Unknown options."fi
写一个脚本:计算100以内所有能被3整除的正整数的和取模,取余:%3%2=1100%55=45
写一个脚本:计算100以内的所有奇书的和以及所有偶数的和;分别显示之
写一个脚本,分别显示当前系统上所有默认的shell为bash的用户和默认shell为/sbin/nologin的用户,并统计各类shell下的用户总数,显示结果形如下:BASH,3users,they are:root,redhat,gentoo
NOLOGIN,2users,they are:bin,ftp
expect远程自动批量登录以及执行命令#! /bin/bashcat /root/iplist | while read line iplist文件中存放了IP地址和密码,每行格式为"IP地址 密码"doA=($line)/usr/bin/expect<<EOFset timeout 5 是设置超时时间的spawn ssh root@${A[0]} spawn是进入expect环境后才可以执行的expect内部命令expect "password:" 这个命令的意思是判断上次输出结果里是否包含“password:”的字符串,如果有则立即返回,否则就等待一段时间后返回,这里等待时长就是前面设置的5秒 send "${A[1]}\r" 用户的登陆密码,这里是root用户,密码是passwd expect "]#" 意思为遇到这个提示符为执行命令开始 send "df -h\r" 意思为发送命令send "pwd\r" 意思为发送命令expect "*]#" 意思为遇到这个提示符为执行命令结束send "logout\r" 退出远程机器EOFdone
#! /bin/bashcat /root/iplist | while read linedoA=($line)/usr/bin/expect<<EOFset timeout 5spawn ssh root@${A[0]}expect { "yes/no" { send "yes\r"; exp_continue}"password:" { send "${A[1]}\r" }}expect "]#"send "df -h\r"send "pwd\r"expect "]#"send "logout\r"EOFdone
expect实现su切换脚本#! /bin/bashcat /root/iplist | while read linedoA=($line)/usr/bin/expect<<EOFset timeout 5spawn ssh weihu@${A[0]}expect { "yes/no" { send "yes\r"; exp_continue}"password:" { send "${A[1]}\r" }}expect "]$"send "su - root\r"expect "密码:"send "${A[2]}\r"send "ifconfig\r"expect "]#"send "pwd\r"expect "*]#"send "logout\r"EOFdone=========================================================================================>
测试:整数测试-le-lt-gt-eq-ne字符测试
!=
>
<
-n
-z
文件测试-e-f-d-r-w-x
if [ $# -gt -1 ]; then
组合测试条件-a:与关系-o:或关系!:非关系
if [ $# -gt 1 -a $# -le 3 ]if [ $# -gt 1 ] && [ $# -le 3 ]
写一个脚本,利用RANDOM生成10个随机数,并找出其中的最大值,和最小值#! /bin/bashdeclare -i MAX=0declare -i MIN=0for i in {1..10}; doMYRAND=$RANDOM[ $i -eq 1 ] && MIN=$MYRANDif [ $i -le 9 ]; thenecho -n "$MYRAND,"elseecho "$MYRAND"fi[ $MYRAND -gt $MAX ] && MAX=$MYRAND[ $MYRAND -lt $MIN ] && MIN=$MYRANDdone
echo $MAX,$MIN
面向过程控制结果顺序结构选择结构循环结构
选择结构:if:单分支,双分支,多分支if condition; thenstatement....fi
if condition; thenstatement....elsestatement....fi
if condition; thenstatement....elif condition2; thenstatement....elsestatement....fi
case语句:选择结构
case switch invalue1)statement....;;value2)statement....;;*)statement....;;esac
#! /bin/bashcase $1 in [0-9])echo "A digit." ;;[a-z])echo "Lower" ;;[A-Z])echo "Upper" ;;*)echo "Special character." ;;esac
只接受参数start,stop,restart,status其中之一#! /bin/bashcase $1 instart)echo "start server...." ;;stop)echo "stop server...." ;;restart)echo "restarting server...." ;;*)echo "basename $0
{start|stop|restrt|status}" ;;esac
写一个脚本,可以接受选项及参数,而后能获取每一个选项,及选项的参数;并能根据选项及参数做出特定的操作,比如#! /bin/bashDEBUG=0ADD=0DEL=0
for i in seq 1 $#
; docase $1 in-v|--verbose)DEBUG=1 shift ;;-h|--help)echo "Usage:basename $0
--add USER_LIST --del USER_LIST -v|--verbose -h|--help" exit 0;;--add)ADD=1ADDUSERS=$2shift 2;;--del)DEL=1DELUSERS=$2shift 2;; #*)
echo "echo "Usage:basename $0
--add USER_LIST --del USER_LIST -v|--verbose -h|--help""
exit 7
;;
esacdone
if [ $ADD -eq 1 ]; thenfor USER in echo $ADDUSERS | sed 's@,@ @g
'; doif id $USER &> /dev/null; then[ $DEBUG -eq 1 ] && echo "$USER exists."elseuseradd $USER[ $DEBUG -eq 1 ] && echo "Add user $USER finished."fidonefi
if [ $DEL -eq 1 ]; thenfor USER in echo $DELUSERS | sed 's@,@ @g
'; doif id $USER &> /dev/null; thenuserdel -r $USER[ $DEBUG -eq 1 ] && echo "$USER exists."else[ $DEBUG -eq 1 ] && echo "$USER not exist."fidonefi
脚本编程控制结构:顺序选择ifcase循环forwhileuntil
while condition; dostatmentdone
进入循环:条件满足退出循环:条件不满足
until condition; dostatmentdone
进入循环:条件不满足退出循环:条件满足
#! /bin/bashread -p "Input something: " STRINGwhile [ $TRING != 'quit' ]; doecho $STRING | tr 'a-z' 'A-Z'read -p "Input something: " STRING
done
#! /bin/bashread -p "Input something: " STRINGuntil [ $STRING == 'quit' ]; doecho $STRING | tr 'a-z' 'A-Z'read -p "Input something: " STRINGdone
#! /bin/bashwho | grep "hadoop" &> /dev/nullRETVAL=$?until [ $RETVAL -eq 0 ]; doecho "hadoop is not come"sleep 5who | grep "hadoop" &> /dev/nullRETVAL=$?doneecho "hadoop is logged in"
for 变量 in 列表; do循环体done
for (( expr1 ; expr2 ; expr3 )); do循环体done
#!/bin/bashdeclare -i sum=0for ((i=1;i<=100;i++)); dolet sum+=$idoneecho $sum
写一个脚本:通过ping命令测试192.168.0.151到192.168.0.254之间的所有主机是否在线,如果在线,就显示"ip is up",其中的ip要换成为真正的ip地址,且以绿色显示如果不在线,就显示"ip is down.",其中的ip要换成为真正的ip地址,且以红色显示要求:分别使用while,until和for循环实现
awk 'PATTERN{ACTION}' file
df -Ph | awk '{print $2}'awk -F: '{print $1,$2}' /etc/passwd
写一个脚本(前提:请为虚拟机新增一块硬盘,假设它为/dev/sdb),为指定的硬盘创建分区:1.列出当前系统上所有的磁盘,让用户选择,如何选择quit则退出脚本;如果用户选择错误,就让用户重新选择;2.当用户选择后,提醒用户确认接下来的操作可能会损坏数据,并请用户确认,如果用户选择y就继续,否则,让用户重新选择;3.抹除那块硬盘的所有分区(提示,抹除所有分区后执行sync命令,并让脚本睡眠3秒钟后在分区):并为其创建三个主分区,第一个为20M,第二个为512M,第三个为128M,且第三个为swap分区类型;(提示:将分区命令通过echo传送给fdisk即可实现)#! /bin/bashecho 'np1
+20Mnp2
+512Mnp3
+128Mt382' w | fisk /dev/hda
fdisk -l 2> /dev/null | grep ^Disk /dev/[sh]d[a-z]'' | awk -F: '{print $1}'dd if=/dev/zero of=/dev/hda bs=512 count=1syncsleep 3
写一个脚本,完成以下功能:说明:此脚本能于同一个repo文件中创建多个yum源的指向;1.接受一个文件名作为参数,此文件存放至/etc/yum.repo.d目录中,且文件名以.repo为后缀;2.在脚本中,提醒用户输入repo id:如果为quit,则退出脚本;否则,继续完成下面的步骤;3.repo name以及baseurl的路径,而后以repo文件的格式将其保存至指定的文件中;4.enabled默认为1,而gpgcheck默认设定为0;5.此脚本会循环执行多次,除非用户为repo id指定为quit#! /bin/bashREPOFILE=/etc/yum.repos.d/$1if [ -e $REPOFILE ]; thenecho "$1 exists."exit 3fi
read -p "Repository ID:" REPOIDuntil [ $REPOID == 'quit' ]; doecho "[$REPOID]" >> $REPOFILEread -p "Repository name: " REPONAMEecho "name=$REPONAME" >> $REPOFILEread -p "Repository Baseurl:" REPOURLecho "baseurl=$REPOURL" >> $REPOFILEecho -e 'enabled=1\ngpgcheck=0' >> $REPOFILEread -p "Repository ID: " REPOIDdone
while,until,for
break:提前退出循环continue:提前结束本轮循环,而进入下一轮循环
#! /bin/bashlet sum=0let i=0while [ $i -lt 100 ]; folet i++if [ $[$i%2] -eq 0 ]; thencontinuefilet sum+=$idone
#! /bin/bashdeclare -i sum=0for i in {1..1000}; dolet sum+=$iif [ $sum -gt 10000]; thenbreakfidoneecho $iecho $SUM
while的特殊用法一:while :;do
done
while的特殊用法二:while read LINE; do
done < /path/to/somefile
#! /bin/bashfile=/ect/passwdlet i=0while read LINE; do[ echo $LINE
| awk -F: '{print $3}' -le 505 ] && continue[ echo $LINE | awk -F: '{print $7}'
== '/bin/bash' ] && echo $LINE | awk -F : '{print $1}' && let i++[ $i -eq 6 ] && breakdone < $FILE
写一个脚本:1.判断一个指定的bash脚本是否有语法错误;如果有错误,则提醒用户键入Q或者q无视错误并退出,其它任何键可以通过vim打开这个指定的脚本;2.如果用户通过vim打开编辑后保存并退出时仍然有错误,则重复第一步中的内容;否则,就正常关闭退出#! /bin/bashuntil bash -n $1 &> /dev/null; doread -p "Syntax error,[Qq] to quit,others for editing: " CHOICEcase $CHOICE inq|Q)echo "somthing wrong,quiting."exit 5;;*)vim + $1;;esacdone
函数:功能,function
代码重用:
库:so
定义一个函数:function FUNNAME { command}
FUNCNAME() { command}
自定义执行状态返回值:return #0-255
接受参数的函数:./a.sh m n$1:m$2:n
#! /bin/bashcat << EOFd|D) show disk usagesm|M) show memory usagess|S) show swap usagesq|Q) quit.EOF
read -p "your choice: " CHOICEuntil [ $CHOICE == 'q' -o $CHOICE == 'Q' ]docase $CHIOCE ind|D) df -lh ;;m|M) free -m | grep '^Mem';;s|S) free -m | grep '^Swap';;*)cat << EOFd|D) show disk usagesm|M) show memory usagess|S) show swap usagesq|Q) quit.EOFread -p "your choice,again: " CHOICEesaccat << EOFd|D) show disk usagesm|M) show memory usagess|S) show swap usagesq|Q) quit.EOFread -p "your choice: " CHOICEdone
#! /bin/bashTWOINT() {
A=9B=7C=$[$A+$B]echo $C}M=11SUM=$[$M+TWOINT
]echo $SUM
#! /bin/bashADDUSER() { USERNAME=$1if ! id -u $USERNAME &> /dev/null; thenuseradd $USERNAMEecho $USERNAME | passwd --stdin $USERNAME &> /dev/nullreturn 0elsereturn 1fi}for i in {1..10}doADDUSER user$ifi [ $? -eq 0 ]; thenecho "add user$i finished."elseecho "Failuser."fidone
#! /bin/bashfunction SHOWMENU { cat << EOFd|D) show disk usagesm|M) show memory usagess|S) show swap usagesq|Q) quit.EOF}SHOWMENUSHOWMENUSHOWMENU
#! /bin/bashTWOSUM() {
echo $[$1+$2]}for i in {1..10}dolet J=$[$i+1]echo "$i plus $J is TWOSUM $i $j
"done
练习:写一个脚本,判定192.168.0.200-192.168.0.254之间主机哪些在线。要求1.使用函数来实现一台主机的判定过程2.在主程序中来调用此函数判定指定的范围内的所有主机的在线情况#! /bin/bashPING() { for i in {200..254}doif ping -c1 -W 1 192.168.0.$i &> /dev/null; thenecho "192.168.0.$i is up."elseecho "192.168.0.$i is down."fidone}PING
#! /bin/bashPING() { if ping -c 1 -W 1 $1 &> /dev/null; thenecho "$1 is up."elseecho "$1 is down."fi}
for i in {200..254}doPING 192.168.0.$idone
for i in {220..254}doPING 172.16.100.$idone
#! /bin/bashPING() { if ping -c 1 -W 1 $1 &> /dev/null; thenreturn 0elsereturn 1fi}
for i in {200..254}doPING 192.168.0.$iif [ $? -eq 0 ]; thenecho "192.168.0.$i is up."elseecho "192.168.0.$i is down."fidone
写一个脚本:使用函数完成1.函数能够接受一个参数,参数为用户名判断一个用户是否存在如果存在,就返回此用户的shell和UID;并返回正常的状态值如果不存在,就说此用户不存在;并返回错误的状态值2.在主程序中调用函数
扩展1:在主程序中,让用户自己输入用户名后,传递给函数来进行判断扩展2:在主程序中,输入用户名判断后不退出脚本,而是提示用户继续输入下一个用户名;如果用户输入的用户不存在,请用户重新输入,但如果用户输入的是q或Q就退出;
=========================================================================================>
二、变量的截取替换
表达式 含义${#string} $string的长度
${string:position} 在$string中, 从位置$position开始提取子串${string:position:length} 在$string中, 从位置$position开始提取长度为$length的子串
${string#substring} 从变量$string的开头, 删除最短匹配$substring的子串${string##substring} 从变量$string的开头, 删除最长匹配$substring的子串${string%substring} 从变量$string的结尾, 删除最短匹配$substring的子串${string%%substring} 从变量$string的结尾, 删除最长匹配$substring的子串
${string/substring/replacement} 使用$replacement, 来代替第一个匹配的$substring${string//substring/replacement} 使用$replacement, 代替所有匹配的$substring${string/#substring/replacement} 如果$string的前缀匹配$substring, 那么就用$replacement来代替匹配到的$substring${string/%substring/replacement} 如果$string的后缀匹配$substring, 那么就用$replacement来代替匹配到的$substring
脚本编程知识点:1.变量中字符的长度:${#VARNAME}
2.变量赋值等:${parameter:-word}:如果parameter为空或未定义,则变量展开为"word":否则,展开为parameter的值:${parameter:+word}:如果parameter为空或未定义,不做任何操作;否则,则展开为"word"值${parameter:=word}:如果parameter为空或未定义,则变量展开为"word",并将展开后的值赋值为parameter${parameter:offset}${parameter:offset:length}:取字串,从offset处的后一个字符开始,取lenth长的字串
3.脚本配置文件/etc/rc.d/init.d/服务脚本服务脚本支持配置文件:/etc/sysconfig/服务脚本同名的配置文件
vim a.confTEST='hello world'
vim a.sh#! /bin/bash. /root/a.confTEST=${TEST:-info}[ -n "$TEST" ] && echo "$TEST"
4.局部变量lcoal VAR_NAME=
a=1test() {
local a=$[3+4]}testfor i in seq $a 10
doecho "$i"done
5.命令mktemp创建临时文件或者目录mktemp /tmp/file.XX-d:创建为目录
6.信号kill -SIGNAL PID1:HUP2:INT9:KILL15:TERM脚本中,能实现信息捕捉,但9和15无法捕捉不了
Ctrl+c:SIGINT
trap命令:trap 'COMMAND' 信号列表
vim showdate.sh#! /bin/bashtrap 'echo "you go..."' INTwhile :dodatesleep 2done
7.一行执行多个语句,语句间用分号分隔#! /bin/bashNET=192.168.0FILE=mktemp /tmp/file.xxxxx
clearup() {
echo "quit...."rm -rf $FILEexit 1}trap 'clearup' INTfor i in {200..254}doif ping -c 1 -W 1 $NET.$i &> /dev/null; thenecho "$NET.$i is up."| tee >> $FILEelseecho "$NET.$i is down."fidone
任务计划:
1.在未来的某个时间点执行一次某任务:atbatch
at 时间at> COMMANDat> Ctrl+d
指定时间:绝对时间:HH:MM,DD.MM.YY MM/DD/YY相对时间:now+#单位:minutes,hours,days,weeks模糊时间:noon,midnight,teatime
命令的执行结果:将以邮件的形式发给安排任务的用户
at -l = atq at -d AT_JOB_ID = atrm AT_JOB_ID
2.周期性地执行某任务cron:自身是一个不间断运行的服务anacron:cron的补充,能够实现让cron因为各种原因在过去的时间改执行而未执行的任务在恢复正常执行一次
cron:系统cron任务:/etc/crontab分钟 小时 天 月 周 用户 任务用户cron任务:/var/spool/cron/USERNAME分钟 小时 天 月 周 任务
时间的有效取值:
分钟:0-59
小时:0-23
天:1-31
月:1-12
周:0-7,0和7都表示周日
时间通配表示:
*:对应时间的所有有效值
3 * * * *
3 * * * 7
13 12 * * *
,:离散时间点:
10,40 * * * *
-:连续时间点
10 02 * * 1-5
/#:对应取值范围内每多久一次
*/3 * * * *
每两小时执行一次:00 /2 每两天执行一次:10 04 /2 *
执行结果将以邮件形式发送给管理员:/3 * /bin/cat /etc/fstab &> /dev/null
cron的环境变量:cron执行所有命令都去PATH坏境变量指定的路径下去找PATH /bin:/sbin:/usr/bin:/usr/sbin
用户任务的管理:crontab-l:列出当前用户的所有cron任务-e:编辑-r:移除所有任务-u USERNAME:管理其用户的cron任务
anacron:cat /etc/anacrontab
service crond statusservice anacron status
Knernel + initrd(busybox制作,提供ext3文件系统模块) + ROOTFS(busybox制作)
make arch/arch/x86/boot/bzImage
硬件驱动:initrdinitrd:仅需要提供内核访问真正的根文件系统所在设备需要的驱动存储设备和文件系统相关的模块系统初始化rc.sysinit:初始化其它硬件的驱动程序
ROOTFS:busybox,init不支持运行级别 /etc/inittab:格式也不尽相同ash,hushbash
内核编译:tar -zxvf linux-2.6.38.5.tar.gz -C /usr/src/cd linux-2.6.38.5ln -sv linux-2.6.38.5 linuxcd linuxmv kernel-2.6.38.1-i686.cfg .configmake memuconfigmake drivers/net/pcnet32.komake arch/x86/或者(make SUBIDR=arch/)
/boot/vmlinuz(ext3,IDE)
/mnt/boot: /dev/hda1/mnt/sysroot: /dev/hda2
1、安装grubgrub-install --root-directory=/mnt /dev/hda
cp /boot/vmlinuz-2.16.18-308.e15 /mnt/boot/vmlinuz
tar -zxvf busybox-1.20.2.tar.gzmkdir busybox-1.20.2/include/mtdcp /usr/src/linux-2.6.38.5/include/mtd/ubi-user.h busybox-1.20.2/inuclude/mtd
cd busybox-1.20.2make menuconfigmake install mkdir /tmp/initrdcp _install/* /tmp/initrd/ -acd /tmp/initrd/mkdir proc sys mnt/sysroot dev tmp lib/modules etc -pvrm -rf linuxrcmknod dev/console c 5 1mknod /dev/null c 1 3
vim init#! /bin/shecho "mounting proc and sys..."mount -t proc proc /procmount -t sysfs sysfs /sys
echo "load ext3 module..."insmod /lib/modules/jbd.koinsmod /lib/modules/ext3.komdev -smount -t ext3 /dev/hda2 /mnt/sysroot
echo "Switch to real_rootfs..."exec switch_root /mnt/sysroot /sbin/init
modinfo jbdmkdinfo ext3把输出的filename信息路径复制到 lib/modules
find . | cpio -H newc --quit -o | gzip -9 > /mnt/boot/initrd.gz
vim /mnt/boot/grub/grub.confdefault=0timeout=3title MageEdu Tiny Linux (2.6.18)root(hda0,0)kernel /vmlinuz ro root=/dev/hda2initrd /initrd.gz
cp -a busybox-1.20.2/_install/* /mnt/sysroot/
cd /mnt/sysrootrm -rf linuxrcmkdir boot root etc/rc.d/init.d var/{log,lock,run} proc sys dev lib/moudles tmp home mnt media -pv
mknod dev/console c 5 1mknod dev/null c 1 3
vim etc/inittab::sysinit:/etc/rc.d/rc.sysinitconsole::respawn:-/bin/sh::ctrlaltdel:/sbin/reboot::shutdown:/bin/umount -a -r
vim /etc/rc.d/rc.sysinit#! /bin/shecho -e "\tWelcome to \033[34mMegeEdu Tiny\033[0m Linux"
echo "mount proc and sys..."mount -t proc proc /procmount -t sysfs sysfs /sys
echo -e "Rmount the rootfs..."mount -t ext3 -o remount,rw /dev/hda2 /
echo "Detect and export hardward information"mdev -s
echo "Mount the ohter filesystem.."mount -a
chmod +x etc/rc.d/rc.sysinit
vim etc/fstabsysfs /sys sysfs defaults 0 0proc /proc proc defaults 0 0/dev/hda1 /boot ext3 defaults 0 0/dev/hda2 / ext3 defaults 1 1
./bincp.sh bash然后吧etc/inittab中的/bin/sh改成/bin/bash
grep -E "^root:" /etc/passwd > /mnt/systoot/etc/passwdgrep -E "^root:" /etc/passwd > /mnt/sysroot/etc/shadowgrep -E "^root:" /etc/group > /mnt/sysroot/group
vim etc/inittab::sysinit:/etc/rc.d/rc.sysinit::respawn:/sbin/getty 9600 tty1::ctrlaltdel:/sbin/reboot::shutdown:/bin/umount -a -r
vim /mnt/sysroot/etc/hostnameHOSTNAME=tiny.magedu.com
vim /mnt/sysroot/ect/rc.d/rc.sysinit#! /bin/shecho -e "\tWelcome to \033[34mMegeEdu Tiny\033[0m Linux"
echo "set the hostname"[ -f /etc/hostname ] && . /etc/hostname[ -z "$HOSTNAME" -o "$HOSTNAME" == '(none)' ] && HOSTNAME=localhosthostname $HOSTNAME
echo "mount proc and sys..."mount -t proc proc /procmount -t sysfs sysfs /sys
echo -e "Rmount the rootfs..."mount -t ext3 -o remount,rw /dev/hda2 /
echo "Detect and export hardward information"mdev -s
echo "Mount the ohter filesystem.."mount -a
cp /etc/issue /mnt/sysroot/ect/
find . | cpio -H newc --quiet -o | gzip > /root/tiny.1.gz
modinfo miimodinfo pcnet32同样复制其模块位置到lib/modules/
在sysinit中末尾添加一行echo "Load ethernet card module..."insmod /lib/modules/...
telnet:远程登录协议,23/tcpC/SS:telnet服务器C:telnet客户端
ssh:Secure SHell,应用层协议,22/tcp通信过程及认证过程是加密的,主机认证用户认证过程加密数据传输过程加密
主机密钥非对称加密Secret keyPublic key密钥交换
ssh v1,v2man-in-middle
sshv2
认证过程:基于口令认证基于密钥认证
协议:规范实现:服务器端、客户端
Linux:opensshC/S服务器端:sshd,配置文件/etc/sshd_config客户端:ssh,配置文件/etc/ssh/ssh_configssh-keygen:密钥生成器ssh-copy-id:将公钥传输至远程服务器scp:跨主机安全复制工具
ssh:ssh USERNAME@HOSTssh -l USERNAME HOSTssh USERNAME@HOST 'COMMAND'
scp:scp SRC DEST -r-ascp SERNAME@HOST:/path/to/somefile /path/to/lcoalscp /path/to/local USERNAME@HOST:/path/to/file
ssh-keygen-t rsa~/.ssh/id_rsa~/.ssh/id_rsa.pub-f /path/to/KEY_FILE-P '':指定加密私钥的密码
公钥追加到远程主机某用户的家目录下的.ssh/anthorized_keys文件或.ssh/authorized_keys2文件中
ssh-copy-id-i ~/.ssh/id_rsa.pubssh-copy-id -i ~/.ssh/id_rsa.pub USERNAME@HOST
dropbear:嵌入式系统专用的ssh服务器和客户端工具服务器端:dropbeardropbearkey客户端:dbclient
dropbear默认使用nsswitch实现名称解析
/etc/nsswitch.conf
/usr/libnss_files*
/usr/lib/libnss3.so
/usr/lib/libnss_files*
dropbear会在用户登录检查其默认shell是否当前系统的安全shell
/etc/shells
主机密钥默认位置:/etc/dropbear/RSA:dropbear_rsa_host_key长度可变,只要是8的整数倍,默认为1024DSS:dropbear_dss_host_key长度固定,默认为1024dropbearkey
tar -zxvf dropbear-2013.56.tar.bz2cd dropbear./configuremake make install
./bincp.sh dropbear dropbearkey dbclient
cd /mnt/sysroot/vim etc/shells/bin/sh/bin/bash/bin/ash/bash/hush
然后在etc/fstab中加一行加载devpts /dev/pts devpts mode=620 0 0
mkdir /dev/pts
dropberkey -t rsa -f /mnt/sysroot/etc/dropbear/dropbear_rsa_host_key -s 2048 dropberkey -t rsa -f /mnt/sysroot/etc/dropbear/dropbear_dss_host_key -s 2048
mkdir usr/libcp -d /lib/libnss_files* /mnt/sysroot/lib/cp -d /usr/lib/libnss3.so /usr/lib/libnss_files.so /mnt/sysroot/usr/lib/ls -l /mnt/sysroot/lib/cp /etc/nsswitch.conf /mnt/sysroot/etc
vim nsswitch.conf只需要保留passwd,shadow,group,hosts这几行
启动小系统,配置IP地址/usr/lcoal/sbin/dropbear [-E -F]
/usr/lcoal/bin/dbclient -l root 172.16.200.1
vim select.sh#! /bin/bashPS3="select your will exec memu:"select i in apache mysql phpdocase $i inapache)echo "apache";;mysql)echo "mysql";;php)echo "php";;esacdone
bash select.sh
find . -maxdepth 1 -type f -name ".txt" -mtime +30 30天之前的文件find . -maxdepth 1 -type f -name ".txt" -mtime -1 一天以内的文件find . -maxdepth 1 -size +50M -type f -exec mv {} /tmp/ \;把大于50M的文件移到/tmp
制作csv格式的文档:echo "ip,hostname,cpu,mem,disk" >> 1.csvecho "10.30.231.98,localhost,inter,1G,500M,40G" >> 1.csv
发邮件格式:mail -s "邮件主题" -c"抄送地址" -b"密送地址" -f 发送人邮件地址 -F 发件人姓名 收件人地址 < "发邮件的内容"