脚本基础2
shell脚本编程 作用:通过命令行解析的方式,自动执行设定好的程序或命令代码。(若将脚本挂到定时任务中,就会自动在非工作时间里自动触发执行程序) ? Shell脚本文件以“.sh”结尾 规范的Shell脚本第一行会指出由哪个程序(解释器)来执行脚本中的内容。在linux bash编程中一般为:#!/bin/bash(表示该脚本运用/bin/bash命令进行解析) ? Shell的输出用echo命令; Python的输出用print命令 ? 执行脚本的方式: 方法一:/bin/sh是bash的软链接,也就是说我么既可以用sh执行也可以用bash执行脚本 # sh yunjisuan.sh # bash yunjisuan.sh 方法二:以绝对路径的方式执行脚本(前提:将该脚本添加x执行权限) # chmod +x yunjisuan.sh # /root/benet/yunjisuan.sh ? 方法三:以source脚本路径的方式执行脚本(等同于“.脚本路径”)只在当前环境生效 # source yunjisuan.sh # . yunjisuan.sh ? 方法四:以相对路径的方式执行脚本(前提:将该脚本添加x执行权限) # ./yunjisuan.sh ? ? 写脚本 (1)vim编辑yunjisuan.sh (2)查看yunjisuan.sh脚本 (3)执行yunjisuan.sh脚本 ? 脚本中书写的命令必须是非交互式的命令!!! ? ? 虽然脚本可以自动化执行,但脚本不会判断命令是否执行成功,因此需要进行逻辑判断 方法一: test命令 判断该字符串表示为文件还是目录 -d 测试是否为目录 -e 测试目录或文件是否存在 -f 测试是否为文件 -l 测试是否为链接文件 -r 测试当前用户是否可读 -w 测试当前用户是否可写 -x 测试当前用户是否可执行 -s 测试文件大小非0时为真(若为非空文件,则为真) -u 测试是否具有SUID属性 -g 测试是否具有SGID属性 -k 测试是否具有sticky bit 粘滞位属性 -z 测试字符串是否为空(zero) file1 -nt file2测试第一个文件是否比第二个文件新(new then) file1 -ot file2 测试第一个文件是否比第二个文件旧(old then) file1 -ef file2 测试第一个文件是否与第二个文件为同一个文件(link之类的文件) ? # test -d 目标路径 # echo $?判断是否是目录,若显示0表示真(是目录),若显示非0则假(不是目录) ? # test -f 目标路径 判断目标是不是文件 # echo $? ? $?返回值参考 0 表示运行成功 2 权限拒绝 1~125 表示运行失败,脚本命令,系统命令错误或参数传递错误; 126 找到该命令,但无法执行 127 未找到要运行的命令 128 命令被系统强制结束 ? ? ? 方法二: 使用“[]”,表示开启判断条件(“[]”两边须有空格) # xx=”welcome” # [ $xx == welcome] && echo “0” || echo “1” 0 “[]”应用于整数(格式:整数1 操作符整数2) -gt(great than)表示大于 -lt(less than)表示小于 -eq(equal)表示等于 -ne (not equal)表示不等于 -ge 表示大于等于 -le表示小于等于 && 逻辑与,表示前一指令为真,执行后一指令,否则不执行 || 逻辑或,表示前一指令为假,执行后一指令,否则不执行 # xx=”44” # if [ -f "$file1" ];then echo 1;else echo 0;fi 相当于# [ -f "file1" ] && echo 1 ||echo 0 ? # [ $xx -eq 34 ] && echo “0” || echo “1” 1 ? 字符串测试 [ -z “字符串” ]? 字符串内容为空 [ -n “字符串” ]? 字符串内容不为空 ? ${#变量名}?? 求变量的字符串位数,判断字符串是否为空 # xx=”123411” # echo ${#xx} 6 # xx=”” # echo ${#xx} 0 ? 脚本的交互式输出模式 方法一: 执行脚本过程中,存在需要用户输入内容的情况,通过read命令进行交互式输入 ? 添加注释给用户: 输入格式:read -p “文本提示” 变量名 输0出格式:echo $变量名 ? ? ? ? ? ? ? ? ? 创建用户名和密码 #!/bin/bash ? User="yunjisuan" Passwd="123456" read -p "请输入用户名" user read -p "请输入密码" passwd [ $User -eq $user ] && echo "YOU ARE RIGHT" || echo “YOU ARE WRONG” [ $Passwd -eq $user ] && echo "YOU ARE RIGHT" || echo "YOU ARE WRONG" ? ? 逻辑测试 “[]”中,-a(&&)表示并且; -o (||)表示或者 !逻辑否 方法二:通过参数传递的方式进行交互式输入 /etc/init.d/ 服务启动脚本 服务启动脚本/etc/init.d/后面写的内容就是参数,通过这个参数进行交互式输入 ? ? ? $# 表示脚本要处理的的参数个数 $? 表示命令或脚本执行状态码 $* 表示横向罗列脚本要处理的所有参数(把所有参数视为整体) [email?protected] 表示横向罗列脚本要处理的所有参数(把所有参数视为单个参数的组合) $0 表示脚本文件的绝对路径或相对路径(脚本文件的执行路径) $1 第一个参数 ? $n 第n个参数 ? 脚本中反引号“``”、“$()”的应用 ? ? ? ? 变量的算数运算 变量的数值运算多用于脚本程序的过程控制,只能进行简单的整数运算,不支持小数运算,整数值得运算主要通过内部命令expr进行。 ? # x=11 # y=22 # expr $x * $y 格式: expr 变量1 运算符变量2... ++ --?? 增加及减少,可前置也可放在结尾 !~? 一元运算的正负号,非,逻辑与位的取反 *?? 乘法 /?? 除法 %? 取余 **? 幂运算 + 加法 -? 减法 <; <=;>; >= 比较符号 == 1+= 相等,不相等 <<? 向左移动 >>? 向右移动 >>>? 填0右移 & 位的与AND ^? 位的异或 |? 位的或 &&? 位的AND ||?? 位的OR ?:? 条件表达式 =; += ;-= ;*=等赋值运算符 ? (())用法(常用于简单的整数运算) “(())”在命令行执行时不需要$符号,但是输出需要$符号 “(())”里所有字符之间有无或多个空格没有任何影响 ? # b=$((1+2**3-4%3)) # echo $b 8 # echo $((1+2**3-4%3)) 8 ? ? ? ? ? ? a++,a--,++a,--a区别 变量a在前,表达式的值为a,然后a自增或自减,变量a在符号后,表达式值自增或自减,然后a值自增或自减。 # a=8 # echo $a 8(a赋值为8) # echo $((a+=1)) #相当于a=a+1 9(a赋值为a+1=9) # echo $((a++)) #a在前,先输出a的值,在加1 9(a赋值为上一值a为9) # echo $a 10(a赋值上一值的9++,9+1为10) # echo $((a--)) 10(a取上一值a为10) # echo $a 9(a取上一值10--,10-1为9) # echo $((++a)) 10(先+1,在取上一值9,1+9=10) # echo $a 10(取上一值10) # echo $((--a)) 9(先-1,取上一值10,10-1=9) # echo $a 9(取上一值9) ? Shell脚本中不支持“i++”表达,可以用C语言的((i++))在shell中表示 或者“let h++” ? ? If条件语句 格式(fi 表示结束) (一)单分支条件判断语句 (1) if??? 条件1 then 动作1 else 动作2 fi (2)(用;分隔) if???? 条件1;then 动作1 else 动作2 fi ? 在vim中编辑yunjisuan.sh脚本 #!/bin/bash read -p "请输入一个数字:" num if [ $num == 60 ];then ?????? echo "猜对了" fi # sh yunjisuan.sh 请输入一个数字:60 猜对了 ? 在vim中编辑yunjisuan.sh脚本 #!/bin/bash read -p "请输入一个数字:" num if [ $num == 60 ];then ?????? echo "猜对了" else ?????? echo "猜错了" fi # sh yunjisuan.sh 请输入一个数字:45 猜错了 ? ? (二)多分支条件判断语句(elif就是else if) ?if?? 条件1;then 动作1 elif? 条件2;then 动作2 else 动作3 fi 查看当前文件的绝对目录 # dirname 目标文件的绝对路径 ? 查看当前文件的基本文件名称 # basename 目标文件的绝对路径 自定义搭建本地yum仓库脚本 (1)移除光盘,再挂载 (2)判断光盘挂载 (3)挂载本地yum仓库脚本 (4)判断一级目录、二级目录是否存在 (5)配置文件手动生成,避免之前被修改过(重定向或echo -e) #!/bin/bash umount /dev/sr0&>/dev/null [ -d /media/cdrom ]|| mkdir -p /media/cdrom(还可以用test和if的方法) mount /dev/sr0 /media/cdrom &>/dev/null if [ $? -ne 0 ];then ??????? echo "请插入光盘" ??????? exit fi [ -d /etc/yum.repos.d ] || mkdir -p /etc/yum.repos.d cd /etc/yum.repos.d mv * /tmp/? echo -e “[local]nname=localnbaseurl=file:///media/cdrom/ngpgcheck=0nenabled=1”>/etc/ yum.repos.d/localyum.repo (或) cat > /etc/yum.repos.d/localyum.repo << FOF [local] name=local baseurl=file:///media/cdrom gpgcheck=0 enabled=1 F0F yum -y clean all &>/dev/null yum makecache &>/dev/null [ $? -eq 0 ] && echo "yum仓库搭建完毕" || echo "缓存建立失败!" ? 配置文件手动生成 用脚本手动生成配置文件,一般用重定向 输入重定向通过FOF标识(任意定义,但成对出现),将FOF之间的内容输入重定向到cat,cat再输出重定向给/etc/yum.repos.d/yum/repo文件 ? ? ? while循环语句 格式: while 条件 do 循环体(指令) done ? ? 休息命令:sleep 1 休息1秒,usleep 1000000 休息1秒,单位微妙 ? 从1到100求和 #!/bin/bash ? i=1 sum=0 while [ $i -lt 100 ] do ?????? ((sum=sum+i)) ?????? ((i++)) done echo $sum ? 守护进程 #!/bin/bash ? while true do ??????? uptime >> /var/log/uptime.log ??????? sleep 2 done ? ? 倒计时 #!/bin/bash ? i=10 while [ $i -gt 0 ] do ??????? echo $i ??????? ((i--)) done ? 无限循环 (1) #!/bin/bash ? read -p "输入:" i while [ $i -gt 0 ] do ??????? echo $i ??????? let i++ done (2) #!/bin/bash ? read -p "输入:" i while : do ??????? echo $i ??????? let i++ done ? 强行中止 # exit ? 防止脚本执行中断的方法 1)sh while01.sh & #放在后台执行 ? for循环语句 格式: for 变量名 in 变量取值列表 do 循环体(指令) done 示例:循环 for ((i=0;i<10:i++)) do ?????? echo $i done ? 打印列表元素 for的三种输出方式 (1) #!/bin/bash ? for i in 1 2 3 4 5 do ??????? echo $i done (2) #!/bin/bash ? for i in {1..5}?? do ??????? echo $i done (3) #!/bin/bash ? for i in `seq 5` do ??????? echo $i done ? ? #!/bin/bash ? h=0 for i in {1..10} do ??????? echo $h ??????? let h++ done ? 开机启动项优化 #!/bin/bash for i in `chkconfig | grep "3:on" | awk ‘{print $1}‘` do ??????? chkconfig $i off done if [ -e sysstat ] ??????? then echo "sysstat exit" ??????? else mkdir -p /media/cdrom ??????? mount /dev/sr0 /media/cdrom ??????? if [ $? -ne 0 ];then ??????????????? echo "FAILED" ??????????????? exit ??????? else yum -y install sysstat ??????????????? if [ $? -ne 0 ];then ??????????????????????? echo "install error" ??????????????????????? exit ??????????????? else echo "install successed" ??????????????? fi ??????? fi fi for h in sshd network crond rsyslog sysstat do ??????? chkconfig $h on done [ $? == 0 ]&& echo "successed" || echo "failed" ? ? 在/yunjisuan目录批量创建文件 #!/bin/bash Path=/yunjisuan [ -d "$Path" ] || mkdir -p $Path for i in `seq 10` do ??????? touch $Path/yunjisuan_$i.html done ? 批量改名 #!/bin/bash Path=/yunjisuan [ -d "$Path" ] || mkdir -p $Path for file in `ls $Path` do ??????? mv $Path/$file "$Path/"`echo $file | sed -r ‘s#yunjisuan(.*).html#linux1.HTML#g‘` done ? ? 批量创建用户并设置密码 #!/bin/bash ? User=yunjisuan Path=/tmp ? for user in ${User}{01..10} do ??????? useradd $user > /dev/null 2>&1 ??????????????? if [ $user -ne 0 ];then ??????????????? echo "$user created failed" ??????????????? echo "scripts begin to rollback" ??????????????????????? for i in ${User}{01..10} ??????????????????????? do ??????????????????????????????? userder -r $i >/dev/null 2>&1 ??????????????????????????????? [ $? -eq 0 ] || exit 1 ??????????????????????? done ??????????????? echo >$Path/usr_passwd ??????????????? exit 1 ??????????????? else ??????????????? passWD=`echo $RANDOM | md5sum | cut -c1-8` (表示取一大串随机数,从这串随机数前截取1-8位) ??????????????? [ -d $Path ] || mkdir $Path ??????????????? echo $passWD | passwd --stdin $user ??????????????? echo "$user:$passWD">> $Path/user_passwd ??????????????? fi done ? ? exit 0 表示正常运行程序并退出程序 exit 1 或exit -1 表示非正常运行导致退出程序 ? echo -n 不换行 ? 获取当前目录下的目录名做为变量列表打印输出 #!/bin/bash Path=`pwd` echo $Path for filename in `ls` do ??????? [ -d ${Path}/${filename} ] && echo $filename done ? 九九乘法表 #!/bin/bash ? for ((i=1;i<10;i++)) do ??????? for ((j=1;j<=i;j++)) ??????? do ??????????????? echo -n "$j * $j =$((i*j))" ??????????????? echo -n " " ??????? done ??????? echo " " done ? ? 显示出1-100的偶数 #!/bin/bash ? for i in {1..100} do ??????? [ $(($i%2)) -eq 0 ] && echo $i done 显示出1000-2000的质数 #!/bin/bash ? for i in {1000..2000} do ??????? [ $(factor $i | awk ‘{print NF}‘) -le 2 ] && echo $i done ? factor命令:分解因数 ? ? Case语句 用途:菜单;启动脚本 case语句适合变量的值少,且为固定的数字或字符串集合。系统服务启动脚本传参的判断多用case语句 格式: case "字符串变量" in ??? 值1) ??????? 指令1 ??????? ;; ??? 值2) ??????? 指令2 ??????? ;; ??? *) ??????? 指令 esac ? 注意:case语句相当于一个if的多分支结构语句 ? 值1的选项 apple) ??? echo -e "@RED_COLOR apple $RES" ??? ;; 也可以这样写,输入2种格式找同一个选项 apple|APPLE) ??? echo -e "$RED_COLOR apple $RES" ??? ;; ? 服务脚本框架 #!/bin/bash . /etc/init.d/functions case $1 in ??????? start) ??????????????? action "服务开始启动"?? /bin/true ??????????????? ;; ??????? stop) ??????????????? action "服务准备停止"?? /bin/false ??????????????? ;; ??????? restart) ??????????????? action "服务准备停止"?? /bin/true ????? ??????????action "服务来时启动"?? /bin/true ??????????????? ;; ??????? *) ??????????????? echo "请输入正确参数" ??????????????? ;; esac ? 在当前脚本引用函数库(绝对路径) Function对应的是action “ ” 路径 /bin/true 表示一个标志 ? ? ? 设置脚本配置启动级别 (1)为脚本设置启动级别 将脚本复制到/etc/init.d/下,vim编辑/etc/init.d/cash.sh脚本 # chkconfig: 35 90 10 (2)在chkconfig中添加脚本 # chkconfig --add case.sh # chkconfig --list case.sh ? (3)设置关闭cash.sh # chkconfig case.sh off ? Shell函数 不论什么编程语言,基本只有三种编程的方法(指如何去编写代码的方法论) 1、面向过程 2、面向对象 3、函数式编程 在shell语言中,只能支持面向过程这种编程方法。 ? 在shell中,function表示函数(function、return可以不写) 格式: function 函数名(){ 命令序列 [return x] } ? 函数名 ? ? ? 函数体只有被调用时才会启动,若要重复启动该函数,只需将函数名重复n遍 ? 源码编译示意 ? ? ? 获取随机数的几种方法 (1)通过系统环境变量$RANDOM # echo $RANDOM 6178 ? # echo $RANDOM 30890 ? # echo $((RANDOM%9)) #输出0~9之间随机数 2 # echo $((RANDOM%9)) ? # echo $((RANDOM%9))$((RANDOM%9)) #输出00~99 随机数 64 ? # echo $RANDOM|md5sum #随机数长短不一,可以用md5sum命令统一格式化 599e328a94329684ce5c92b850d32f26 - ? ? (2)通过openssl产生 # openssl rand -base64 8 aND8WMRM6vQ= ? # openssl rand -base64 8 RsRdRq/9vi4= ? # openssl rand -base64 8|md5sum b1108cafbc2291392e41d2c914360138 - ? # openssl rand -base64 10 1frkA2kIJODxqQ== ? ? (3)通过时间获得随机数(date命令详解见下页文档) # echo $(date +%N) 361599138 ? # echo $(date +%t%N) 950526316 ? (4)Urandom # head /dev/urandom | cksum 621330951 2535 ? # head /dev/urandom | cksum 404398617 2470 ? ? (5)UUID # cat /proc/sys/kernel/random/uuid 8a6c5bbe-2d42-44ac-9ef1-3e7683a613e3 ? # cat /proc/sys/kernel/random/uuid c828c209-5b5f-4bc7-917c-678ed4215988 ? # uuidgen 961dc354-81b2-4564-9b85-6095ed4bc7b5 ? 循环控制语句break、continue、exit、return 作用:用于循环结构中控制循环语句 ? break n:n表示跳出循环的层数,如果省略n表示跳出整个循环(只跳出所在位置的循环) continue n:n表示退出到第n层继续循环,如果省略n表示跳过本次循环,忽略本次循环剩余代码,进入循环的下一次循环exit n:退出当前shell程序,n为返回值,n也可以省略,在下一个shell里通过$?接收这个n值 return n:用在函数里,做为函数的返回值,用于判断函数执行是否正确。和exit一样,如果函数里有循环,也会直接退出循环,退出函数 ? break n:n表示跳出循环的层数,如果省略n表示跳出整个循环 #!/bin/bash for ((i=0;i<=5;i++)) do ??????? [ $i -eq 3 ] && break ??????? echo $i done echo "ok" ? ? break只跳出所在位置的一个整个循环循环 ? ? ? continue n:n表示退出到第n层继续循环,如果省略n表示跳过本次循环,忽略本次循环剩余代码,进入循环的下一次循环 ? #!/bin/bash ? for ((i=0;i<=5;i++)) do ??????? [ $i -eq 3 ] && continue ??????? echo $i done echo "ok" ? exit n:退出当前shell程序,n为返回值,n也可以省略,在下一个shell里通过$?接收这个n值 ? #!/bin/bash ? for ((i=0;i<=5;i++)) do ??????? [ $i -eq 3 ] && exit 2 ??????? echo $i done echo "ok" ? return n:用在函数里,做为函数的返回值,用于判断函数执行是否正确。和exit一样,如果函数里有循环,也会直接退出循环,退出函数 ? #!/bin/bash ? function xxx() { ??? ????for ((i=0;i<=5;i++)) ??????? do ??????????????? [ $i -eq 3 ] && return 7 ??????????????????????? echo $i ??????? done ??????? echo "ok" } ? xxx echo $? ? shell脚本的调试 (1)使用dos2unix处理脚本 从windows编辑的脚本到Linux下需要使用这个命令 (2)使用echo命令调试 在变量读取或修改的前后假如echo $变量,也可在后面使用exit退出脚本,这样可以不用注释后边代码 (3)利用bash的参数调试 sh [-nvx] ? 1)要记得首先用dos2unix对脚本格式化 ? ping -c 1 ip地址? ?-c ping的次数? -i 每次ping的间隔时间 -w deadline时间 ? #!/bin/bash for ip in 192.168.214.{1..254} do ??????? ping -c 1 $ip &> /dev/null ??????? if [$? -eq 0 ];then ??????????????? echo "$ip正常状态" ??????? fi done ? ? ? ? ? date命令 作用:用来显示或设定系统的日期与时间。 ? 参数 -d<字符串>:显示字符串所指的日期与时间。字符串前后必须加上双引号; -s<字符串>:根据字符串来设置日期与时间。字符串前后必须加上双引号; -u:显示GMT; --help:在线帮助; --version:显示版本信息。 %H 小时(以00-23来表示) %I 小时(以01-12来表示) %K 小时(以0-23来表示) %l 小时(以0-12来表示) ?%M 分钟(以00-59来表示) %P AM或PM %r 时间(含时分秒,小时以12小时AM/PM来表示) %s 总秒数。起算时间为1970-01-01 00:00:00 UTC %S 秒(以本地的惯用法来表示)。 %T 时间(含时分秒,小时以24小时制来表示) %X 时间(以本地的惯用法来表示) %Z 市区 %a 星期的缩写 %A 星期的完整名称 %b 月份英文名的缩写 %B 月份的完整英文名称 %c 日期与时间,只输入date指令也会显示同样的结果 %d 日期(以01-31来表示) %D 日期(含年月日) %j 该年中的第几天 %m 月份(以01-12来表示) %U 该年中的周数 %w 该周的天数,0代表周日,1代表周一,以此类推 %x 日期(以本地的惯用法来表示) %y 年份(以00-99来表示) %Y 年份(以四位数来表示) %n 在显示时,插入新的一行 %t 在显示时,插入tab MM 月份(必要) DD 日期(必要) hh 小时(必要) mm 分钟(必要) ss 秒(选择性) ? 实例 格式化输出: date +"%Y-%m-%d" 2015-12-07 输出昨天日期: date -d "1 day ago" +"%Y-%m-%d" 2015-11-19 2秒后输出: date -d "2 second" +"%Y-%m-%d %H:%M.%S" 2015-11-20 14:21.31 传说中的 1234567890 秒: date -d "1970-01-01 1234567890 seconds" +"%Y-%m-%d %H:%m:%S" 2009-02-13 23:02:30 普通转格式: date -d "2009-12-12" +"%Y/%m/%d %H:%M.%S" 2009/12/12 00:00.00 apache格式转换: date -d "Dec 5,2009 12:00:37 AM" +"%Y-%m-%d %H:%M.%S" 2009-12-05 00:00.37 格式转换后时间: date -d "Dec 5,2009 12:00:37 AM 2 year ago" +"%Y-%m-%d %H:%M.%S" 2007-12-05 00:00.37 加减操作: date +%Y%m%d?????????????? #显示前天年月日 date -d "+1 day" +%Y%m%d?? #显示前一天的日期 date -d "-1 day" +%Y%m%d?? #显示后一天的日期 date -d "-1 month" +%Y%m%d #显示上一月的日期 date -d "+1 month" +%Y%m%d #显示下一月的日期 date -d "-1 year" +%Y%m%d? #显示前一年的日期 date -d "+1 year" +%Y%m%d? #显示下一年的日期 ? 设定时间: date -s????????? #设置当前时间,只有root权限才能设置,其他只能查看 date -s 20120523 #设置成20120523,这样会把具体时间设置成空00:00:00 date -s 01:01:01 #设置具体时间,不会对日期做更改 date -s "01:01:01 2012-05-23" #这样可以设置全部时间 date -s "01:01:01 20120523"?? #这样可以设置全部时间 date -s "2012-05-23 01:01:01" #这样可以设置全部时间 date -s "20120523 01:01:01"?? #这样可以设置全部时间 ? 检查一组命令花费的时间: #!/bin/bash start=$(date +%s) nmap man.linuxde.net &> /dev/null end=$(date +%s) difference=$(( end - start )) echo $difference seconds. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |