第二部分:shell脚本编程

1.bash变量类别:
(1)用户变量:分为全局变量(默认)和局部变量(需使用local限定词)。作用范围仅限于当前源程序文件,仅对于当前shell进程有效且对当前shell的子shell也无效(bash:在当前shell启动子进程;exit:退出子进程;pstree查看进程树)
(2)环境变量:在程序运行时需要设置
(3)位置变量:在对参数判断和命令退回值判断时使用
  (4) 特殊变量

2.bash变量的声明(可声不声)和赋值(若复制内容有空格需加引号):
declear:
  -i:声明为整型
  -a:声明为数组
  -r:声明变量为只读


3.ash的引号:引用
 1.单引号:强引用
 2.双引用:弱引用
 3.反引用:命令替换


4.引用变量值:
 $varname或${varname}

5.撤销变量(释放变量空间)(一般不使用):
unset varname
只读变量:不能撤销变量
readonly  xxx=xxx

6.shell的特殊字符:
这些字符本身有特殊意义,若要打印显示字符表面本身,需使用\转意。
常见特殊字符:
#:shell脚本中的注释
~:主目录,相当于$HOME,例:cd ~
`:命令替换符,例:`pwd`,退回命令执行的结果
$:变量表达式符号
&:让命令在后台运行(此符号紧加在命令后面)
*:字符串通配符
(:启动子shell
):停止子shell
\:转意字符
|:管道
;  :命令分隔符

'  :强引用
"  :弱引用
<  :输入重定向
>  :输出重定向
/  :路径名目录分隔符
?  :单个任意字符
!  :管道行逻辑NOT
[ ]:开始和结束字符集通配符
{ }:开始和结束命令块
注:大括号操作符{...}允许我们使用shell字符串操作的更多高级功能,即字符串处理运算符


(1)字符串的变量替换运算符:
${varname:-word} //用途:如果变量未定义,则返回默认值。varname存在且非null,返回varname否word

${varname:=word} //用途:如果变量未定义,则设置变量为word。
varname存在且非null,返回varname否将其置为word并退回其值

${varname:+word} //用途:用于测试变量存在。
varname存在且非null,返回word否null

${varname:?message} //用途:用于捕捉由于变量未定义而导致的错误。
varname存在且非null,返回varname否打印message并退出当前脚本


//每个变量都是可选,若省略冒号,则每个定义的“存在且非”改为“存在”,即变量运算符只判断变量是否存在。

(2)字符串模式匹配运算符:
${varname#pattern}
//如果 模式 匹配 变量取值的开头处,则删除匹配的最短部分并退回剩下部分

${varname##pattern}
//如果 模式 匹配 变量取值的开头处,则删除匹配的最长部分并退回剩下部分

${varname%pattern}
//如果 模式 匹配 变量取值的结尾处,则删除匹配的最短部分并退回剩下部分

${varname%%pattern}
//如果 模式 匹配 变量取值的结尾处,则删除匹配的最长部分并退回剩下部分

${varname/pattern/string}
${varname//pattern/string}
//将varname中匹配模式的最长部分替换为string。第一种格式中,只有匹配的第一部分被替换;第二种格式中,所有匹配的部分都被替换。
如果模式以#开头,则必须匹配varname的开头。
如果模式以%开头,则必须匹配varname的结尾。
若果string为空,匹配部分被删除。
如果varname为@或*,操作被依次应用于每个位置参数,并且扩展为结果列表


例;假设path的值为/home/prince/desktop/long.file.name
范例1:若${path#/*/},则为prince/desktop/long.file.name
范例2:若${path##/*/},则为long.file.name
范例3:若${path%.*}, 则为/home/prince/desktop/long.file
范例4:若${path%%.*}, 则为/home/prince/desktop/long
范例5:若${path/prince/ollir},则为/home/ollir/desktop/long.file.name



7.位置参数(0-9)可直接引用,即$0-$9,但超过这个范围必须用括号括起来,如${10}
常见位置变量:
$0:表示脚本自己,即脚本名字
$?:前一个命令运行退回值,0表示命令运行成功,非0表示失败
$#:命令变量的个数
$*:命令的所有变量参数



8.函数
(1)函数使用规则
1)函数必须先定义后使用
2)函数中使用exit命令退出脚本,return命令退回到原本调用函数的地方
3)使用export -f 可以将函数导出到子shell中
4)使用soure或dot命令可以将保存在其他文件中的函数装入当前脚本
5)使用declare -f 可以找到登录会话中定义的函数。declare -F 可以查看函数名
6)若要系统启动时自动加载函数,则source $HOME/.profile。注:该函数已经写入例如:$HOME/.profile的文件中


(2)定义函数
格式:
2.1)
function funcname ()
{
    shell commands
}


2.2)
funcname ()
{
    shell commands
}


(3)删除定义的函数
unset -f funcname
//-f参数提示unset命令删除的是函数





9.逻辑操作:
(1)NOT(!):用惊叹号取反,判断条件失败时进行某些操作
(2)AND(&&):连接多个conditions条件进行判断测试(真真为真)
(3)OR(||):只要两个或多个条件中有一个成功,则整个判断成功


10.条件控制与流程控制
(1)if/else语句
if/else是shell内置,用于判断当某条件成立时,则执行某些命令,常见于选择项不多的情况。
使用if/else条件测试情况:
1)shell变量的值
2)文件字符特性
3)命令运行结果

(2)if/else格式:


 if   condition
then
    statements

 elif condition
then
    statements...

 else condition
then
    statements...
 if


(3)if语句中test条件测试运用:
test expression=[ expression ]=` expression `

3.1)test整数测试符:
 -eq:等于
 -gt:大于
 -lt:小于
 -ne:不等于
 -le:小于等于
 -ge:大于等于

3.2)test字符串测试符:
 3.2.1)双目操作符:
  ==   两字符相同
  !=   两字符不相同
  >
  >=
  <
  <=

3.2.2)单目操作符:
-z $var 字符空为真,不空为假
-n $var 字符空为假,不空为真  
 
3.3)test文件属性测试(多为单目):

-f   判断是否为普通文件
-d   判断是否为目录
-l   判断是否为链接
-e   /path/to/somewhere 判断文件是否存在
-r   判断对当前用户是否有读权限
-w   判断对当前用户是否有写权限
-x   判断对当前用户是否有执行权限
-b   file为块设备文件
-c   file为字符设备文件
-p   file为管道
-O   你是file的所有者
-G   file的组ID匹配你的ID
file1 -nt file2      file1比file2新
file1 -ot file2      file1比file2旧


3.4)组合条件:
!:取反
-a:连接两个条件取与操作(与条件)
-o:连接两个条件取或操作(或条件)

例:
[-e /tmp/mytest] || mkdir /tmp/mytest 即:
[! -e /tmp/mytest] && mkdir /tmp/mytest

[-e /tmp/mytest -a -d /tmp/mytest ] || cd /tmp/mytest 即
[-e /tmp/mytest ] && [-d /tmp/mytest] || cd /tmp/mytest

[-e /etc/init.d/functions] && source /etc/init.d/functions

[-x /etc/init.d/network ] && /etc/init.d/network start



(4)case语句
case也是一个流程控制结构,它可以用更精细的方式表达if-elif类型的语句

1)语法格式:
case expression in
    pattern1)
       statements;;
    pattern2)
       statements;;
    pattern3 | pattern4)
       statements;;
    ...
esac

//pattern之间都可以由管道字符(|)分割的几个模式组成。在这样的情况下,如果expression匹配其中任意一个模式,其相应的语句即被执行。模式匹配按照顺序依次执行,直到匹配上为止。如果都不匹配,则不执行任何操作。



11.循环控制:
(1)for循环
用于遍历整个对象、数字列表,依次执行每个独立对象、数字的循环内容,对象可以是命令行参数、文件名、任何可以以列表格式建立的东西
1.1)for循环格式:
for name [in list]      //遍历list中的所有对象
do
    ...
done

//list为名称列表,我们在for循环中对名称列表中的每个对象进行相应操作。可以通过命令/模式匹配等操作来获取名称列表,
例1:
for file in `find . -iname "*.mp3"`   
do
    mpg123 $file
done

例2:
for file in *.mp3
do
    mpg123 $file
done

//mpg123是命令行程序,播放mp3文件。这两个例子都可以遍历mp3文件,并依次播放,但例1是遍历当前目录中的所有mp3文件,例2是仅仅遍历当前目录下的所有mp3文件。使用find命令会层层深入文件夹,依次查找,而直接列出只会包含当前目录的文件夹

1.2)如果省略in list , 则默认为in "$@",即命令行参数的引用列表

for name             //循环命令行参数
do
    case $name in
    -f) ...            //进行-f参数相关的操作
    -d) ...            //进行-d参数相关的操作
    esac
done



(2)while/until循环
允许代码段在某些条件为真或直到其为真时重复运行
2.1)while语法格式:
while condition
do
    statements
done
 

      until语法格式:
until condition
do
    statements
done

//while与until语句唯一不同之处在于如何判断condition的退出状态,当condition的退出状态为真时,while语句循环继续运行,until语句循环退出。
//condition可以是简单的命令/列表,或者是包含&&或||连接的命令。和if语句中的test一样。


2.2)例:
path=$PATH:  \\当$PATH复制到一个参数path中,并在末尾加冒号

while [ -n $path ];\\当path不为空时    
do
    ls -ld ${path%%:*} \\ls -ld列出显示path中的第一个目录     path=${pat#*:}      \\截去path中的第一个目录和冒号,                      当path被截成空字符串("")时,退出循环
done


2.3)跳出循环
break和continue语句允许对循环的运行精确控制,当循环体的嵌套次数超过1层时,可以传递给break或continue参数,来控制它们跳出循环或重新执行循环。注:continu用于在循环中提早开始下一轮循环,即达到循环体一次全部运行完之前。

2.3.1)语法格式:
while condition1    \\第一个循环体
do  ...
    while conditon2     \\第二个循环体
    do ...
         break 2/continue 2  \\跳出或继续2层循环
    done
done
...            \\break跳到此处继续执


2.3.2)例子:

path=$PATH

while true
do
    if [ -z $path ]
    then
    break        \\如果path为空(""),则退出循环
    fi
    ls -ld ${path%%:*}
    path=${path#*:}
done

\\while true 是一种惯用用法,用于创造一个无限循环,永远执行(与until false语句功能相同)






脚本案例:
1.变量及LAMP导航菜单编写案例
#!/bin/bash
#by authors yhx 2016.8.11

echo -e "\033[32mplease select menu follow:\033[1m"

echo "1)安装apache服务器"
echo "2)安装mysql服务器"
echo "3)安装php服务器"
echo "4)配置LAMP WEB架构"

echo "...................................."



2.IF条件语句各种案例演练
#!/bin/bash
#by authors yhx 2016.8

score=$1

if [ -z $score ]; then
    echo "usage: {$0 60|80.}"
fi

if [[ $score -gt 85 ]] then
    echo "very good"

elif [[ $score -gt 75 ]] then
    echo "good"

elif [[ $score -gt 60 ]] then
    echo "pass!"

else
    echo "no pass!"
fi




xxxxxxxxxxxxxxxx更多内容将进一步更新,敬请期待xxxxxxxxxxxxxxxxxxx

xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx


xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

由于小菜目前能力有限,以上内容可能有所差错,还望各大神能多多赐教,感谢!!!