env 查看环境变量
set 显示环境变量(包括局部变量)
设置环境变量:export 变量名=value
变量名=value,export 变量名
取消变量 unset 变量名
环境变量的初始化过程:
先加载/etc/profile 全局变量文件
在执行/etc/profile.d的目录下的脚本文件
运行$HOME/.bash_profile用户环境变量文件---在执行$HOME/.bashrc
单引号:里面是什么就输出什么,六亲不认
双引号:会解析变量的

需要将命令的结果作为变量内容:
用单引号~~ cmd=ls
或者() CMD=$(ls)

在使用awk的时候,我们习惯先用echo 加符号输出变量在通过管道给awk,进而控制变量输出结果
echo $quan |awk '{print $0}'
QQQQ
echo "$quan" |awk '{print $0}'
QQQQ
echo '$quan' |awk '{print $0}'
$quan

定义变量的技巧:
变量名只能为字母、数字或下划线,只能字母或下划线开头
驼峰写法

shell中的特殊变量:
特殊的位置参数: $0 $1 $2 ....${10} ${11}
$0当前执行shell脚本的文件名
$# 获取当前执行shell脚本的总参数个数
$ 所有参数 加双引号"$" 所有参数视为一个字符串
$@ 不带双引号的时候都是一样,带了双引号后,还是分别为字符串

set 可以设置位置变量参数:set -- “I am” handsome boy
$1 $2 $3
shift 可以使变量位置向左移一位

shell进程中的特殊变量:
$? 上一条命令执行成功或失败,0为成功,非0为失败
多用于判断是否源码安装一步一步成功
$$ 获取当前进程shell脚本的进程号
$?应用:当对服务器进行备份的时候,我们会执行完关键命令后,
通过返回值确认是否数据完整
判断脚本或函数等程序是否成功
若在函数里面调用执行“exit 数字” 则会返回这个数字给“$?”变量
如果是函数里,则通过“return 数字 ” 把这个数字以函数返回值的形式给“$?”
/etc/init.d/rpcbind

bash shell内置变量的命令:echo eval exec export read shift
echo 输出信息
-n 不换行输出内容
-e 解析转义字符
转义字符:\n 换行
(加引号) \r 回车
\t tab
\b 退格
\v 纵向制表符
[root加quan油 ~]$echo quan ;echo -n zhi
quan
zhi[root加quan油 ~]$echo -n quan ;echo zhi
quanzhi
echo -e "quan\nzhi"
quan
zhi
eval args 当shell程序执行到eval语句时,shell读入参数args,并组合成新的命令再执行
exec 命令参数 在不创建子进程的前提下,执行指定的命令,执行完之后,该进程自动终止
read 从标准输入读取字符串等信息
shift:移位

运算命令:
(()) 用于整数运算的常用运算符
((i+1)) 用echo $((i=i+1))输出其值
i=$((i+1)) 将表达式运算后的值付给i
((8>7&&5==5)) 进行比较操作,用于条件判断
echo $((2+1)) 直接输出计算结果
[root加quan油 SH]$a=9
[root加quan油 SH]$echo $((a++))
9
[root加quan油 SH]$echo $a
10
[root加quan油 SH]$echo $((++a))
11
[root加quan油 SH]$echo $a
11
注意:echo $((a++)) echo $((a--)) 显示运算前的值,即a的值
echo $((--a)) echo $((++a)) 显示的是运算后的值
在(())使用变量时可以忽略变量前的$ echo $((my+1))

expr用法:expr(evaluate(求值) expression(表达式)) 
        既可以运算整数,也可以用于字符串长度,匹配等处理
    注意: 计算时,运算符和数字之间都需要空格
            乘号要反斜线转义
    eg:expr 9 + 1
        i=`expr 9 + 1`
        i=`expr $i + 1`变量需要用反引号括起

    判断一个变量值或字符串是否为整数
        原理:利用expr计算时变量或字符串必须为整数的规则,把变量和一个整数(非零)
            相加,判断命令返回是否为0,0——成功为整数
        #!/bin/bash
        expr $1 + 1 &> /dev/null
        if [ $? -ne 0 ];then
            echo "char"
        else
            echo "int"
        fi

    判断扩展名是否符合要求 注意运算的时候都要加空格
    #!/bin/bash
    if expr "$1" : ".*\.sh" &>/dev/null   
     then
        echo "thie name is right"
    else 
    echo "you must rename to $1.sh"
    fi
    通过expr计算字符串的长度
    #!/bin/bash
    for N in quan zhi qiang 
    do
    if [ `expr length $N ` -le 4  ]
        then
            echo $N
    fi
        done

bc 交互式计算,命令行计算
echo 9+9|bc
echo `seq -s "+" 10`=`seq -s "+" 10|bc`(其中seq为生成数字序列 -s 分隔符)
1+2+3+4+5+6+7+8+9+10=55
awk 计算小数很准确
    echo "9.9 9.8"|awk '{print (($1-3)*$2)}'
    67.62

基于shell变量输入read命令
shell变量可以直接赋值或脚本传参外,还可以使用read命令标准输入
read 参数 变量名
参数:-p messege 设置提示信息
-t time 设置等待输入时间,单位默认为s

Shell脚本的条件测试:
最常用的为:[ 测试表达式 ] 两边必须有空格 且里面如果要使用&& || < > 这些只用在[[ ]]
需用-a -o -gt -lt 代替
[[ 测试表达式 ]]
test 测试表达式
((测试表达式))
test -f file && echo 1 ||echo false,使用&& || 带空格美观一点

[ -f /data/sh ] && echo 1 || echo false 可以使用man test 来进行表达式的书写

文件测试描述符
    -d 文件 directory 文件 存在且为目录为真
    -f 文件 file  文件存在且为普通文件为真
    -e 文件 exist 文件存在为真
    -r 文件 read 文件存在且为可读为真
    -s 文件 size 文件存在且文件大小不为0为真
    -w 文件 write 文件存在且可写为真
    -x 文件 executable 文件存在且可执行为真
    -L 文件 link 文件存在且为连接文件为真
    f1 -nt f2  newer than 文件1比文件2 新。以文件修改时间为准
    f1 -ot f2  older than 文件1比文件2 旧 。修改时间为准
    注意:测试变量的时候最好加上双引号
        [ -d "$QUAN" ] && echo "yes" || echo "no"
        也可以用测试描述符代替if
        [ 条件1 ] && {
            命令1
            命令2
            命令3
        }
        if [ 条件1 ]
            then
                命令1
                命令2
                命令3
        fi 

字符串测试操作符
    -n "str"  字符串长度不为0为真 no zero
    -z “str”    字符串长度为0 则为真
    “str1” = “str2”     两个字符串相等为真 ==代替=
    “str1” != “str2”        两个字符串不等为真
    注意:字符串一定要用“”括起来
            =  != 两边要有空格
    [ -n "" ] && echo "sb" || echo "bs"
    bs

整数二元比较操作符
    [] 和test中   (()) 和[[]]中
        -eq             ==或=            相等,equal
        -ne             !=              不相等,no equal 
        -gt             >               大于,greater than
        -ge             >=              大于等于 greater equal
        -lt             <               小于 less than
        -le             <=              小于等于 less equal 
    注意:两端还是要空格
    [ $A -eq $B ] && echo "A=B" || echo "A!=B"
逻辑操作符:
    [] 和 test中        [[]] 和 (())
     -a                     &&(可用在表达式外部)
     -o                     ||(可用在表达式外部)
     -!                     !  

企业案例:
    如果传入数字等于1,就打印one 如果等于2,就打印two,其他提示输入不对并退出
    #!/bin/bash

read -p "please input a number: " innum
[ "$innum" = "1" ] && { #普通字符比较多的使用字符串的语法,使用整数比较容易出错,除非确定是整数
echo "one"
exit 1
}
[ "$innum" = "2" ] && {
echo "two"
exit 2
}
[ "$innum" = "1" -a $innum = "2" ] && {
echo "input error"
exit 3
}

[[ "$A" =~ [1-3]  ]] && echo 8 判断A是否为1或2或3,用到通配符,使用[[]]
8

if条件语句
单分支格式:if 条件测试表达式
then
指令
if
或者
if 条件测试表达式 ;then
指令
fi
多分支格式:if 条件测试表达式
then
指令集1
else
指令集2
fi

        if 条件测试表达式
            then
                指令集1
        elif 条件测试表达式
            theb
                指令集2
        else 
            指令集3
        fi 
    多分支elif的写法,每个elif后面都要then,最后一个else没有then

Shell函数
格式:function 函数名() {
指令
return n
}
函数的执行:执行不带参函数:直接输入函数名即可——不要带小括号
注意:执行时 ,函数名前的function和函数后的小括号都不带
定义在前,执行在后
return是退出函数,可以设置退出的值,给当前的程序使用
如果函数发在文件当中,可以使用source或 . 来加载使用
函数内会使用local定义局部变量,离开函数后消息

            执行带参函数:  函数名 参数1 参数2 
            注意:shell的位置参数也可以当成函数的参数
                    此时父脚本的参数临时被函数参数掩盖或隐藏
                    $0依旧是父脚本的名称
                    函数的参数变量是在函数体里面定义个的
    注意:实现函数和执行脚本文件分离
    可以通过source或者.加载脚本functions中的命令或者参数
        里面有一个函数叫action 用法如下:
            action “字符串”   /bin/true或者/bin/false 
        显示如下:字符串                     [  OK  ]

case条件语句:
case "变量" in
值1)
指令1
;;
值2)
指令2
;;
..
..
..
)
指令3
esac
注意:每个值之后的指令结尾要加 ;;最后一个可以不加
字符串加颜色:echo -e 可以识别转义字符,特殊字符
\e 开始颜色
[1;31m 其中1代表加粗显示(不同的数字,代表不同意思) 详细可以man console_codes
31m--37m代表设置前景色,即字符串颜色
\e[0m 关闭所用属性
\e[1m 设置高亮度
\e[4m 下划线
\e[5m 闪烁
\e[7m 反显
\e[8m 消隐
\e[30m -- \e[37m 前景色
\e[40m -- \e[47m 背景色
echo -e "\e[1;31m\e[4m "quanzhiqinag" \e[0m"
quanzhiqinag (带下划线)
注意:main $
执行main函数,利用$*接受到的命令行的所有参数,并传入到main函数当中

while循环
格式 while 条件测试语句
do
指令
done
条件测试语句成立的时候,执行语句
until循环
until 条件测试语句
do
指令
done
测试语句不成立时进入循环语句

shell中的休息命令:sleep 1 休息一秒
                    usleep 1000000 休息一秒
    注意: 在进行死循环的时候最好要加上sleep命令进行控制循环的频率,否者会消耗大量
            系统资源

shell脚本后台运行知识
使用&后台运行脚本 sh  111.sh &
crl+c 停止执行当前脚本或任务
ctl+z 暂停执行当前的脚本或任务

防止执行脚本中断的方法:
        sh 111.sh &
        nohup 111.sh & 
        screen保持回话,在执行脚本 ,一般要先安装在使用这个命令
        screen  -x 加入已存在的screen回话
                -ls 显示所有的screen作业
                -S  指定screen作业名称创建

定义菜单类型的范范:
cat <

while按行读取文件的方法:
exec读取文件
eg:exec sum=0
while read line
do
cmd
done
cat读取文件:
cat file |while read line
do
cmd
done
while结尾done处通过输入重定向读取文件
while read line
do
cmd
done

总结:while主要是执行守护进程,适用于频率小于1分钟循环处理,加sleep 和usleep控制频率
case语句,主要用于系统启动脚本时传入少量固定规则字符串的情况下
打印菜单,多适用于cat here 文档替换

for循环——主要用于执行有限次的循环

for 变量名 in 变量取值列表(可以空格隔开)
do
指令
done

打印乘法口诀的结果
#!/bin/bash
for n1 in seq 1 +1 9
do
for n2 in seq 1 +1 9
do
if [ $n1 -ge $n2 ]
then
echo -n "$((n1*n2)) "
fi
done
echo ""
done
注意 echo -n " "

生成随机数的犯法;
1)使用系统变量$RANDOM 0-32767 加密性不好,利用md5sum并截取需要的位数
echo "$RANDOM" |md5sum|cut -c 1-8
2)通过openssl产生随机数
openssl rand -base64 8
3)通过时间date 获得随机数
date +%s%N %s从linux系统开始到现在的秒数,%N纳秒
4)通过UUID生成随机数
UUID全称为通用唯一识别码(Universally Unique Identifier,UUID)
是一个软件建构的标准,亦为自由软件基金会Open Software Foundation OSF
的组织在分布式计算环境Distributed Computin Environment DCE领域的一部分

    cat /proc/sys/kernel/random/uuid
5)expect附带的mkpasswd生成
    mkpasswd命令依赖于expect 必须安装

    mkpasswd -l 9 -d 2 -c 3 -C 3 -s 1
    -l 指定密码长度   默认为9   length
    -d 指定密码中的数字数量  默认为2   digits
    -c 指定密码中小写字母的数量     默认为2    lowercase chars
    -C 指定密码中大写字母的数量     默认为2        upper chars
    -s 指定密码中的特殊字符数量     默认为1        special chars
以上都必须有

Select 循环介绍
主要用于显示菜单
select 变量名 in 变量取值列表(可以空格隔开)
do
cmd
done
eg:select name in a b c d
do
echo $name
done
显示为:1) a 自动加标号
2) b
3) c
4) d
#? 这个是默认提示符
其中:PS3 就是控制select循环的提示符的变量
REPLY 就是菜单项对应的数字 即用户输入的数字变量
PS3="echo "please input the num you want:""
select CH in "install lamp" "install lnmp" "quit"
do
case $CH in
"install lamp")
Install lamp
;;
"install lnmp")
Install lnmp
;;
"quit")
echo "see you"
return 3
;;
*)
echo "input Error"
esac
done

Shell脚本后台运行
sh fiel.sh & 后台运行
ctl +c 停止

shell 数组
定义: 1) array=(quan zhi qiang) 每个变量值之间要用空格进行分隔
2) 动态定义数组:array=($(命令))
或者 array=(命令)

打印数组元素:echo ${array[i]} i是从零开始的
                echo ${array[*]} 整个数组的内容
                echo ${#array[*]} 数组元素的个数
数组的删除:unset 数组[下标]
            不加下标,默认是清除整个数组所有的数据
数组的截取和替换:
    截取:echo ${array[*]:1:3} 从下标为1的元素开始截取,共截取3个数组元素
数组的替换:
    echo ${arary[*]/1/b} 将数组中的1 替换成为b  
        ${数组名[*或@]/查找字符/替换字符}  
        注意:该操作不会改变原先数组的内容,于sed修改

脚本开发的规范:、
1) 第一行为 使用的脚本解释器
2)最好加上版本版权等信息
3)尽量不使用中文注释,如果非要加中文 export LANG="zh_CN.UTF-8"
4) 脚本的扩展名应给为.sh
模块的启动和停止脚本命名:start_模块名.sh stop_模块名.sh
监控脚本通常以 _mon.sh 为后缀
控制脚本一般以
_ctl.sh 为后缀

5) 脚本应该放在固定的路劲下
6) 成对的括号一次性打出来
7) 流程控制语句一次性格式写完,再写内容
8) 字符串赋值时,等号左右不能有空格
9) 设当的缩进使代码美观可读
10)全局变量应该全部大写 SHELL 局部变量最好使用驼峰法Shellquan 即单词首字母大写
11)变量前后有字符使用{} 来引用变量 变量为字符串时 加双引号"${QUAN}"
变量为整数时,最好直接使用 $QUAN
12) 函数命名 单词首字母大写 TestUtl 最好都加上return
13)尽量把功能进行子函数的封装
14)缩进的规范:一般使用四个空格缩进

脚本调试的方法:
使用dos2unix 命令来格式化windows下开发的脚本 dos2unix file.sh

1)使用echo命令调试:一般在可能出错的地方,特别是变量附近
                        加入echo 输出 变量 并退出exit 不在执行以下的命令
2)使用bash命令参数调试
    sh [-nvx] file.sh
    -n 不会执行该脚本,仅查询脚本语法是否有问题,并给出错误
    -v  先将脚本输出,在执行脚本,有错误则暑促错误
    -x  将执行脚本内容及即时输出显示到屏幕上,最有用的参数
        注意:程序段会前面会显示+ 表示为程序代码 由PS4决定
            PS4='+${LINENo}' 显示行号

3)用set 命令调试部分脚本
    set -n
    set -v 
    set -x 开启调试功能
    set +x 关闭调试功能
    直接将set -x  set +x 加入脚本中需要调试的位置,运行脚本就无需 sh -x 了

shell脚本开发环境的配置和优化实践
vim 编写sh脚本自动添加注释:
autocmd BufNewFile .py,.cc,*.sh, exec ":call SetTitle()"
func SetTitle()
if expand("%:e") == 'sh'
call setline(1, "#!/bin/bash")
call setline(2, "####################################################")
call setline(3, "#DATE: ".strftime("%F-%T"))
call setline(4, "#NAME: ".expand("%"))
call setline(5, "#AUTHOR: QuanZhiQiang")
call setline(6, "#E-MAIL: [email protected]")
call setline(7, "#TEL: 13145710069")
call setline(8, "####################################################")
endif
endfunc

linux中的信号以及trap命令
信号是由一个整数构成的异步消息,由某个进程发给其他进程,也可以是用户特定键发生的异常事件
由系统发给某个进程

信号列表:kill -l 或者 trap -l 命令 可列出各种信号
HUP 1 挂起,通常因终端掉线或用户退出引发
INT 2 中断,通常因按下Ctrl+c 组合键引发
QUIT 3 退出,通常因按下Ctrl+\ 组合键引发
ABRT 6 中止,通常因某些严重的执行错误引发
ALRM 14 报警,通常用来处理超时
TERM 15 终止,通常在系统关机时发送
TSTP 20 停止进程的运行,但该信号可以被处理和忽略,通常因按下Ctrl+z组合键引起

通常需要忽略的信号包括:
    HUP INT QUIT TSTP TERM ,脚本中可以使用数字也可以使用信号名字

trap命令用于指定,接受到信号后将要采取的行动
    常见用途是在脚本程序被中断时完成的清理工作,或者屏蔽用户非法使用某些信号,
    注意:在使用信号名时,需要省略SIG前缀

    trap  cmd  signal
    cmd:是接受到信号应该采取的行动,命令可以用;隔开  signal 接收到到的信号
eg:trap ’echo quan ‘ 2  注意:一定是单引号

用stty -a 可以列出中断信号与键盘对应的信息

trap ‘’  2  屏蔽信号 单引号里面不用填东西
trap ‘:’ 2  恢复信号,单引号里面加冒号

EXPECT 自动化交互式程序
是一个自动交互式软件,基于TCL(Tool Command Language)脚本编程