-- 第1天:变量,判断 第2天:循环 第3天:选择结构,函数,正则表达式,数组 第4天:awk 第5天:sed expect 脚本加密 shell 基本来说就是一组命令,按照顺序执行(类似批处理)。 它是解释型的,意味着它不需要编译,所以shell是需要声明类型的。 命令 + 固定格式 + 基本语法 + 思想 = shell 执行脚本 ./xxx.sh --要求有执行权限,并且一定要声明shell类型(#!/bin/bash或都#!/bin/sh) sh xxx.sh 或 bash xxx.sh --不需要有执行权限,也可以不声明shell类型 sh -x xxx.sh --可以显示执行过程,帮助排错 变量: 利用export把自定义变量转化为环境变量 [root@dns ~]# a=1 [root@dns ~]# env |grep a=1 [root@dns ~]# set |grep a=1 a=1 [root@dns ~]# export a=1 [root@dns ~]# env |grep a=1 a=1 [root@li www]# a=1 [root@li www]# bash --进入到子bash [root@li www]# echo $a --子bash里看不到此变量值 [root@li www]# exit --退到父bash exit [root@li www]# export a=1 --使用export命令转化为环境变量 [root@li www]# bash [root@li www]# echo $a 1 --再在子bash里可以看到此变量值 [root@li test]# cat 1.sh #!/bin/bash export aaa=111 --第一个脚本的变量加export,才能在第二脚本里调用 sh 2.sh [root@li test]# cat 2.sh #!/bin/bash echo $aaa 变量的定义 [root@li ~]# a=3 [root@li ~]# echo $a 3 declare 或 typeset 定义变量 [root@li ~]# b=3+3 [root@li ~]# echo $b 3+3 declare [root@li ~]# declare -i c=3+3 [root@li ~]# echo $c 6 变量定义的规则: 1,区分大小写,同名称但大小写不同的变量名是不同的变量 [root@li www]# a=2 [root@li www]# A=3 [root@li www]# echo $a 2 [root@li www]# echo $A 3 2,定义时的格式要注意,等号两边不能有空格,对于有空格的字符串做为赋值时,要用引号引起来 B="hello world" B='hello world haha' --单引号和双引号在这里都可以,后赋值的会覆盖前面的赋值 --在脚本里注意引号的相互嵌套,要成对出现 3,单引号与双引号的区别,单引号内的变量或者特殊字符仅为一般字符,但双引号内的变量或者特殊字符可以保持它的变量特性 [root@li ~]# echo '$B' $B [root@li ~]# echo "$B" hello world haha 4,变量名可以是字母或数字或下划线,但是不能以数字开头 [root@li ~]# c123=aaa [root@li ~]# echo $c123 aaa [root@li ~]# 123c=aaa bash: 123c=aaa: command not found [root@li ~]# _abc11122=3 --可以以下划线开头 [root@li ~]# echo $_abc11122 3 5,变量赋值可以有多个 例如 echo $PATH ,以":"分隔(这里准确来说还是一个值) 6,变量的获取方式: $变量名 ${变量名} [root@li ~]# echo $a 3 [root@li ~]# echo ${a} 3 [root@li ~]# echo ${a} 12345 [root@li ~]# echo ${a:1:2} --切片的方式:1表示从第二个开始,2表示截2个字符 23 [root@li ~]# echo ${a:2:2} 34 -------------------------------- file=/dir1/dir2/dir3/my.file.txt 我们可以用 ${ } 分别替换获得不同的值: ${file#*/}:拿掉第一条 / 及其左边的字符串:dir1/dir2/dir3/my.file.txt ${file#*1/}:拿掉第二条 / 及其左边的字符串:dir2/dir3/my.file.txt ${file##*/}:拿掉最后一条 / 及其左边的字符串:my.file.txt ${file#*.}:拿掉第一个 . 及其左边的字符串:file.txt ${file##*.}:拿掉最后一个 . 及其左边的字符串:txt ${file%/*}:拿掉最后条 / 及其右边的字符串:/dir1/dir2/dir3 ${file%%/*}:拿掉第一条 / 及其右边的字符串:(空值) ${file%.*}:拿掉最后一个 . 及其右边的字符串:/dir1/dir2/dir3/my.file ${file%%.*}:拿掉第一个 . 及其右边的字符串:/dir1/dir2/dir3/my 记忆的方法为: [list]# 是去掉左边(在鉴盘上 # 在 $ 之左边) % 是去掉右边(在鉴盘上 % 在 $ 之右边) 单一符号是最小匹配﹔两个符号是最大匹配。[/list] ${file:0:5}:提取最左边的 5 个字节:/dir1 ${file:5:5}:提取第 5 个字节右边的连续 5 个字节:/dir2 我们也可以对变量值里的字符串作替换: ${file/dir/path}:将第一个 dir 提换为 path:/path1/dir2/dir3/my.file.txt ${file//dir/path}:将全部 dir 提换为 path:/path1/path2/path3/my.file.txt 利用 ${ } 还可针对不同的变量状态赋值(没设定、空值、非空值): ${file-my.file.txt} :假如 $file 没有设定,则使用 my.file.txt 作传回值。(空值及非空值时不作处理) ${file:-my.file.txt} :假如 $file 没有设定或为空值,则使用 my.file.txt 作传回值。 (非空值时不作处理) ${file+my.file.txt} :假如 $file 设为空值或非空值,均使用 my.file.txt 作传回值。(没设定时不作处理) ${file:+my.file.txt} :若 $file 为非空值,则使用 my.file.txt 作传回值。 (没设定及空值时不作处理) ${file=my.file.txt} :若 $file 没设定,则使用 my.file.txt 作传回值,同时将 $file 赋值为 my.file.txt 。 (空值及非空值时不作处理) ${file:=my.file.txt} :若 $file 没设定或为空值,则使用 my.file.txt 作传回值,同时将 $file 赋值为 my.file.txt 。 (非空值时不作处理) ${file?my.file.txt} :若 $file 没设定,则将 my.file.txt 输出至 STDERR。 (空值及非空值时不作处理) ${file:?my.file.txt} :若 $file 没设定或为空值,则将 my.file.txt 输出至 STDERR。 (非空值时不作处理) ----------------------------------- [root@li ~]# basename /boot/grub/grub.conf grub.conf 扩展a=1234567890,我要得到4567这几个字符 # echo ${a:3:4} # echo $a|cut -c4-7 # echo $a|awk '{print substr($0,4,4)}' # echo $a|sed -r 's/(...)(....)(.*)/\2/' 7,取消变量的命令 unset 变量名 [root@li ~]# unset a [root@li ~]# echo $a 8,别的变量定义方式 rpm -qf `which mount` ls /lib/modules/`uname -r`/ --执行符号的使用,执行符号是tab键上面的那个符号 scp /root/Desktop/eicar.com 2.2.2.36:`pwd` [root@li /]# a=`which mount` --这样定义 [root@li /]# echo $a /bin/mount [root@li /]# a=$(uname -r) [root@li /]# echo $a 2.6.18-164.el5 练习:求现在到1970年相隔多少天 # echo $[`date +%s`/86400] # echo $(($(date +%s)/86400)) $( ) 等同于 执行符号 ` `,但是如果要嵌套使用,使用` `符号就不行,要用$();但如果不是嵌套的使用` `是可以的,如a="`which mount` `which yum`" [root@dns shell01]# a=$(rpm -qf `which mount`) [root@dns shell01]# echo $a util-linux-2.13-0.52.el5 [root@dns shell01]# a=$(rpm -ql $(rpm -qf `which mount`) |grep /bin/mount) [root@dns shell01]# echo $a /bin/mount $(( )) 等同于 $[ ] --这两个是运算符号 [[ ]] 这是在比较条件里做匹配的写法 下面五种符号的作用: $() $(()) $[] ${} ` ` [[ ]] 9,使用read做交互式变量定义 # read -p "输入你的名字:" name 输入你的名字:张三 ====================================================== 管道 cut cut -d"分隔符" -f列数 cut -c4-7 截取第4到第7的字符数 grep 正则表达式 wc wc -l 查多少行 wc -L 查文件最长的行有多少字符(可用于算单行的字符长度) wc -m 查文件总的字符数(但每行都会把换行符也算一个字符) sort -r 反向排序 -n 以数字来排 -f 大小写不敏感 -t 分隔符 -k 接数字代表第几列 例:把/etc/passwd的用户以uid大小来进行倒序排序 # sort -nr -t":" -k3 /etc/passwd uniq -c 计数统计 例:统计/etc/passwd里最后一列/bin/bash,/sbin/nologin等各有多少个 # cut -d":" -f7 /etc/passwd |sort |uniq -c ===================================================== 重定向 # mail -s "11111" root < /etc/fstab # ping -c 1 10.1.1.1 &> /dev/null # ping -c 1 10.1.1.1 >& /dev/null # ping -c 1 10.1.1.1 > /dev/null 2>&1 --这三条都是把标准输出和错误输出都扔到/dev/null设备 # cat passwdfile --一个存放密码的文件,里面密码123,写两次 123 123 # passwd user1 < passwdfile > /dev/null 2>&1 --可以修改密码,并且把正确或错误信息都扔给了黑洞设备 # ssh 10.1.1.110 < passwd Pseudo-terminal will not be allocated because stdin is not a terminal. root@10.1.1.110's password: --ssh是不可以的,需要用到expect脚本 EOF end of file #注意下面这两种区别 cat > /tmp/abc <> /tmp/abc < /etc/yum.repos.d/rhel-source.repo < /dev/null wget http://10.1.1.35/test.txt 调度LVS web1 web2 web3 输入一个文件,判断它属于哪种类型 ============================================================= ; --前面执行完,不管成功与否,都执行后面 && --前面执行完,只有前面执行成功了,才执行后面 || --前面执行完,只有前面执行失败了,才执行后面 # ./configure ; make ;make install --执行完前面,再执行后面 # ./configure && make && make install --前面执行成功,再执行后面的 # [ -e /etc/fstab ] && echo "存在" # [ -e /etc/fstab ] || echo "不存在" # [ -e /etc/fstab ] || echo "不存在" && echo "存在" --错误写法 # [ -e /etc/fstab ] || echo "存在" && echo "不存在" --错误写法 # [ -e /etc/fstab ] && echo "存在" || echo "不存在" --正确写法 ========================================== 练习:read输入一个普通文件,判断当前用户对它是否可读,可写,可执行(最好用一个普通用户来做,用root用户测试会有一定问题) 练习: 判断一个文件是否为死链接(死链接的条件是文件是链接文件,但是不存在) 练习:使用read让用户输入它的名字,性别(对性别进行判断),年龄(判断是否有18岁成年) 如:李四 男 15 , 则最后echo出 “李四小子,你好!" 李四 男 20 ,则最后echo出 “李四先生,你好!" 王五 女 15 ,则最后echo出 "王五小姐,你好!" 王五 女 20 ,则最后echo出 "王五女士,你好!" 提示:echo xxxx |grep [^0-9] --查找字符串里是否有非数字的字符 练习:写一个在尚观网络检查的脚本,当你不能上外网时,则直接执行这个脚本,会详细告诉你是哪里有问题(网卡问题,还是IP问题,还是网关问题,还是DNS问题) --自动批量检查的思想 练习:改写上面的找笔记脚本,把它拷到/bin/下叫findnotes 改后的要求: 1,当输入findnotes -e时就直接相当于查找ule的内容,后面只需要输入查找的关键字就可以显示结果(-s对应shell,-m对应mysql,-a对应ula,-o对应oracle) 2,当输入findnotes -h时,会显示到帮助 3,当后面接的参数不是-h,-e,-s,-m,-a,-o其中之一时,则报参数错误 4,如果参数超过一个的话,就报错,并显示帮助 练习,假如我现在要写一个自动安装软件的脚本,安装的目录由用户自定义,如果安装此软件最少需要3G大小,请写一个判断空间是否足够安装的脚本 --要考虑你安装的目录是否被单独挂载的问题 --(因为被单独挂的话就要计算挂载它的分区还有多大。如果没有单独挂,就要计算/还有多大) 练习,用read输入一个年份,判断是否为闰年 (能被4整除,但不能被100整除就是闰年,能被400整除也是闰年) 提示:+ - * / ** % 练习,写一个注册用户及其密码的小程序,保留它的用户和密码到一个文件上(实际环境应该由数据库).要实现密码长度大于等于8位,两次输入要相同(要求密码长度最少为8个字符,不能以数字开头) ) --但如果上面条件,再加一条(不能为纯字母),又应该如何解决? 提示:可以使用正则表达式 grep [^a-Z] 练习:在上面的基础上,再做用户登录,还要动态验证码功能(这里做不了字母,就直接用四个数字做验证码,然后在10秒内输入正确的验证码,才能继续.错误或超时,都需要重新产生验证码).最后实现,用户验证登录. 提示:echo $[$RANDOM%10]产生一个0-9的随机数字