标签:接触shell
bash是linux学习中重要的一环,他可以批量处理linux命令,完成多个单任务的组合。提高运维效率!
bash编程语法一:变量
bash变量类别:
本地变量:只对当前shell进程有效的变量;对其它shell进程无效,包当前shell进程的子进程;
VAR_NAME=VALUE
变量赋值:向变量的存储空间保存数据
变量引用:${VAR_NAME}
"":弱引用,里面的变量会被替换;
‘‘:强引用,里面的所有字符都是字面量,直接输出;
[root@www ~]# varname=aolens.com
[root@www ~]# echo ${aolens.com}
-bash: ${aolens.com}: bad substitution
[root@www ~]# echo ${varname}
aolens.com
[root@www ~]# echo "$varname"
aolens.com
[root@www ~]# echo ‘$varname‘
$varname
环境变量:对当前shell进程及其子shell有效,对其它的shell进程无效;
定义:export VAR_NAME=VALUE
导出:export VAR_NAME
使用env命令显示所有的环境变量
撤消变量:unset VAR_NAME
只读变量:readonly VAR_NAME
局部变量:对shell脚本中某代码片断有效;通常用于函数本地;
local VAR_NAME=VALUE
位置变量:用来接受变量指定位置的参数。
$1(第一个参数), $2(第二个参数), ..., ${10}
$0(代表变量本身)
特殊变量:
$# | 位置参数的个数 | 
"$*" | 代表"$1 $2 $3 $4..."空格间隔 | 
"$@" | 所有的位置参数(每个都独立“$1” "$2" "$3" ...) | 
${#*} | 传递到脚本中的命令行参数的个数 | 
${#@} | 传递到脚本中的命令行参数的个数 | 
$? | 返回值 | 
$$ | 脚本的进程ID(PID) | 
| $! | 运行在后台的最后一个作业的进程ID(PID) | 
set可以设置某个环境变量的值。清除环境变量的值用unset命令。如果未指定值,则该变量值将被设为NULL。
变量命名:
1、不能使用程序中的关键字(保留字);
2、只能使用数字、字母和下划线,且不能以数字开头;
3、要见名知义
变量类型:
精确数值:整数
近似数值:浮点型
字符型:char,string
布尔型:true, false
bash的配置文件:
profile类:为交互式登录的用户提供配置
全局:/etc/profile、/etc/profile.d/*.sh
用户:~/.bash_profile
bashrc类:为非交互式的用户提供配置
全局:/etc/bashrc
用户:~/.bashrc
bash编程:解释器
shell脚本:
第一行,顶格:
    #!/bin/bash-->用来识别是否bash脚本
    #!/usr/bin/python
其它的以#开头的行均为注释,会被解释器忽略;可作为脚本内命令说明。
bash编程:测试脚本
-n: 语法测试,测试是否存在语法错误
-x: 模拟单步执行,将每一步的执行过程结果都显示出来。
bash编程:for循环语句
for第一种格式:
for 变量名 in 列表; do
循环体
done
循环体:依赖于调用变量来实现其变化;
循环可以嵌套;
退出条件:遍历列表完成
    for i in {1..10};do
        echo $i
    done
for的第二种使用格式 :
for ((初始条件;测试条件;修改表达式)); do
循环体
done
先用初始条件和测试条件做判断,如果符合测试条件则执行循环体,再修改表达式。否则直接跳出循环。
    for((i=0;i<10;i++));do    
        echo $i
    done
bash编程:while、until循环语句
while格式:
while 测试条件; do
循环体
done
    read -p "enter num" num    
    while [ $num -gt 10 ];do
        echo  ‘num>10’
    read -p "enter num" num
    done
测试条件为真,进入循环;测试条件为假,退出循环;
测试条件一般通过变量来描述,需要在循环体不变量地改变变量的值,以确保某一时刻测试条件为假,进而结束循环;
until格式:
until 测试条件; do
循环体
done
测试条件为假,进入循环;测试条件为真,退出循环;
测试条件一般通过变量来描述,需要在循环体不变量地改变变量的值,以确保某一时刻测试条件为真,进而结束循环;
bash编程:交互式编程
read [option] “prompt”
        -p:直接指定一个变量接受参数
-t timaout:指定等待接受参数的时间
-n:表示不换行
    例如:输入用户名,可返回其shell    
    #!/bin/bash
    read -p "Plz input a username: " userName
    if id $userName &> /dev/null; then
        echo "The shell of $userName is `grep "^$userName\>" /etc/passwd | cut -d: -f7`."
    else
        echo "No such user. stupid."
    fi
bash编程:逻辑运算
&&(与): condition1 && condition2 == [ condition1 -a condition2 ]
||(或): condition1 || condition2 == [ condition1 -o condition2 ]
       !(非):! condition   == [ -not  condition ]
bash编程:if选择
if: 三种使用格式
(1)单分支的if语句:表示条件测试状态返回值为值,则执行选择分支;
if 测试条件; then
选择分支
fi
(2)双分支的if语句:两个分支仅执行其中之一
if 测试条件; then
选择分支1
else
选择分支2
fi
   练习:通过命令行给定一个文件路径,而后判断:
   如果此文件中存在空白行,则显示其空白行的总数;
   否则,则显示无空白行;
   if grep "^[[:space]]*$" $1 &> /dev/null; then
   echo "$1 has $(grep "^[[:space]]*$" $1 | wc -l) blank lines."
   else
   echo "No blank lines"
   fi
注意:如果把命令执行成功与否当作条件,则if语句后必须只跟命令本身,而不能引用。
(3)多分支的if语句:
if 条件1; then
分支1
elif 条件2; then
分支2
elif 条件3; then
分支3
...
else
分支n
fi
    练习:传递一个用户名给脚本:
    如果此用户的id号为0,则显示说这是管理员
    如果此用户的id号大于等于500,则显示说这是普通用户
    否则,则说这是系统用户;
    #!/bin/bash
    #
    if [ $# -lt 1 ]; then
        echo "Usage: `basename $0` username"
        exit 1
    fi
    if ! id -u $1 &> /dev/null; then
        echo "Usage: `basename $0` username"
        echo "No this user $1."
        exit 2
    fi
    if [ $(id -u $1) -eq 0 ]; then
        echo "Admin"
    elif [ $(id -u $1) -ge 500 ]; then
        echo "Common user."
    else
        echo "System user."
    fi
bash编程:case选择
case语句:有多个测试条件时,case语句会使得语法结构更明晰
case格式:
case 变量引用 in
PATTERN1)
分支1
;;
PATTERN2)
分支2
;;
...
*)
分支n
;;
esac
PATTERN:类同于文件名通配机制,但支持使用|表示或者;
a|b: a或者b
*:匹配任意长度的任意字符
?: 匹配任意单个字符
[]: 指定范围内的任意单个字符
    写一个脚本,使用格式:    
    script.sh {start|stop|restart|status}
    1) start: 创建/var/lock/subsys/script.sh
    2) stop: 删除此文件
    3) restart: 先删除文件,再创建文件
    4) status: 如文件存在,显示running,否则,显示stopped
    #!/bin/bash
    srv=`basename $0`
    lockFile="/var/lock/subsys/$srv"
    [ $# -lt 1 ] && echo "Usage: $srv {start|stop|restart|status}" && exit 4
    [ $UID -ne 0 ] && echo "Only root." && exit 5
    if [ "$1" == ‘start‘ ]; then
       if [ -f $lockFile ]; then
            echo "$srv is running."
            exit 7
       else
            touch $lockFile
            [ $? -eq 0 ] && echo "Starting $srv OK."
       fi
    elif [ "$1" == ‘stop‘ ]; then
        if [ -f $lockFile ]; then
            rm -f $lockFile
            [ $? -eq 0 ] && echo "Stopping $srv OK."
        else
            echo "$srv is stopped yes."
            exit 6
        fi
    elif [ "$1" == ‘restart‘ ]; then
        if [ -f $lockFile ];then
            rm -f $lockFile
            [ $? -eq 0 ] && echo "Stopping $srv OK."
        else
            echo "$srv is stopped yet."
        fi
        touch $lockFile
        [ $? -eq 0 ] && echo "Starting $srv OK."
    elif [ "$1" == ‘status‘ ];then
        if [ -f $lockFile ];then
            echo "$srv is running."
        else
            echo "$srv is stopped."
        fi
    else
        echo "Usage: $srv {start|stop|restart|status}" && exit 9
    fi
bash编程:算术运算
bash会对数字执行隐式的类型转换
declare -i Var_Name=Integer_Value:定义一个整型变量
let Var_Name=EXPRESSION
$[EXPRESSION]
$((EXPRESSION))
命令:expr ARG1 OP ARG2
操作符:
+, -, *, /, %(取模), **(次幂)
双目运算符:需要至少两个操作数
bash编程:条件测试
命令执行成功与否即为条件测试
测试类型:根据比较时的操作数的类型
整型测试:整数比较
字符测试:字符串比较
文件测试:判断文件的存在性及属性等
        (1)整型测试:
例如 [ $num1 -gt $num2 ]
| -gt | 大于 | 
| -lt | 小于 | 
| -ge | 大于等于 | 
| -le | 小于等于 | 
| -eq | 等于 | 
| -ne | 不等于 | 
| -n string(单目测试) | 是否不空,不空则为真,空则为假 | 
| -z string (单目测试) | 是否为空,空则为真,不空则假 | 
(2)字符串测试:
例如:[[ "$str1" > "$str2" ]]
| > | 大于 | 
| < | 小于 | 
| >= | 大于等于 | 
| <= | 小于等于 | 
| == | 等于 | 
| != | 不等于 | 
(3)文件测试:
| -a file | 存在则为真;否则则为假 | 
| -e file | 存在则为真;否则则为假 | 
| -f file | 存在并且为普通文件,则为真;否则为假 | 
| -d file | 存在并且为目录文件,则为真;否则为假 | 
| -L/-h file | 存在并且为符号链接文件,则为真;否则为假 | 
| -b | 存在并且为块设备,则为真;否则为假 | 
| -c | 存在并且为字符设备,则为真;否则为假 | 
| -S | 存在并且为套接字文件,则为真;否则为假 | 
| -s | 存在并且飞空,则为真;否则为假 | 
| -p | 存在并且为命名管道,则为真;否则为假 | 
| -r | 文件可读为真,否则为假 | 
| -w | 文件可写为真,否则为假 | 
| -x | 文件可执行为真,否则为假 | 
bash编程:函数
语法:
function F_NAME {
函数体
}
F_NAME() {
函数体
}
可调用:使用函数名
函数名出现的地方,会被自动替换为函数;
脚本:
函数的返回值:
函数的执行结果返回值:代码的输出
函数中的打印语句:echo, print
函数中调用的系统命令执行后返回的结果
执行状态返回值:
函数体中最后一次执行的命令状态结果
自定函数执行状态的返回值:return #
函数可以接受参数:
在函数体中调用函数参数的方式同脚本中调用脚本参数的方式:位置参数
$1, $2, ...
$#, $*, $@
    示例:服务脚本示例    
    #!/bin/bash
    #
    # chkconfig: 2345 67 34
    #
    srvName=$(basename $0)
    lockFile=/var/lock/subsys/$srvName
    start() {
        if [ -f $lockFile ];then
    echo "$srvName is already running."
    return 1
        else
    touch $lockFile
    [ $? -eq 0 ] && echo "Starting $srvName OK."
    return 0
         fi
    }
    stop() {
        if [ -f $lockFile ];then
    rm -f $lockFile &> /dev/null
    [ $? -eq 0 ] && echo "Stop $srvName OK" && return 0 
        else
    echo "$srvName is not started."
    return 1
        fi
    }
    status() {
        if [ -f $lockFile ]; then
    echo "$srvName is running."
        else
    echo "$srvName is stopped."
        fi
        return 0
    }
    usage() {
         echo "Usage: $srvName {start|stop|restart|status}"
         return 0
    }
    case $1 in
    start)
    start
    ;;
    stop)
    stop ;;
    restart)
    stop
    start ;;
    status)
    status ;;
    *)
    usage
    exit 1 ;;
    esac
bash编程:信号捕捉
trap ‘COMMAND‘ SIGNALE
        第一种形式的trap命令在shell接收到signal list清单中数值相同的信号时,将执行双
        引号中的命令串。
        trap ‘commands‘ SININT(表示关闭进程)
        trap "commands" SIGINT(表示关闭进程)       
    脚本:写一个脚本,能够ping探测指定网络内的所有主机是否在线?当没有执行完时可接收ctrl+c命令退出!    
    #!/bin/bash
    #
    quitScript() {
        echo "Quit..."
    }    
    trap ‘quitScript; exit 5‘ SIGINT
    cnetPing() {
        for i in {1..254}; do
    if ping -c 1 -W 1 $1.$i &> /dev/null; then
         echo "$1.$i is up."
    else
         echo "$1.$i is down."
    fi
         done
    }
    bnetPing() {
        for j in {0..255}; do
    cnetPing $1.$j 
        done
    }
    anetPing() {
        for m in {0..255}; do
    bnetPing $1.$m
        done
    }
    netType=`echo $1 | cut -d"." -f1`
    if [ $netType -ge 1 -a $netType -le 126 ]; then
        anetPing $netType
    elif [ $netType -ge 128 -a $netType -le 191 ]; then
        bnetPing $(echo $1 | cut -d‘.‘ -f1,2)
    elif [ $netType -ge 192 -a $netType -le 223 ]; then
        cnetPing $(echo $1 | cut -d‘.‘ -f1-3)
    else
        echo "Wrong"
        exit 2
    fi
bash编程:shift
       如果没有数字,只有shift 就是跳过一个参数获取下一个参数,如果加上数字,比如shift 2 ,跳过两个参数获取下一个参数
  比如:
  $1=1 $2=2 $3=3
  那么shift后
  $1=2 $2=3 $3=""
  如果shift 2后
  $1=3 $2="" $3=""
    练习:写一个脚本,使用形式如下所示    
    showifinfo.sh [-i INTERFACE|-a] [-v]
    要求:
    1、-i或-a不可同时使用,-i用于指定特定网卡接口,-a用于指定所有接口;
    显示接口的ip地址
    2、使用-v,则表示显示详细信息
    显示接口的ip地址、子网掩码、广播地址;
    3、默认表示仅使用-a选项;
    #!/bin/bash
    #
    verbose=0
    allInterface=0
    ifflag=0
    interface=0
    while [ $# -ge 1 ]; do
        case $1 in
        -a)
    allInterface=1
            shift 1
    ;;
         -i)
    ifflag=1
    interface="$2"
    shift 2
    ;;
         -v)
    verbose=1
    shift
    ;;
         *)
    echo "wrong option"
    exit 2
    ;;
         esac
    done
    if [ $allInterface -eq 1 ]; then
        if [ $verbose -eq 1 ]; then
    ifconfig | grep "inet addr:"
        else
    ifconfig | grep "inet addr:" | awk ‘{print $2}‘ 
        fi
    fi
    if [ $ifflag -eq 1 ]; then
        if [ $verbose -eq 1 ]; then
    ifconfig $interface | grep "inet addr:"
        else
    ifconfig $interface | grep "inet addr:" | awk ‘{print $2}‘ 
        fi
    fi
bash编程:循环控制 return,break
continue: 提前进入下一轮循环
用于条件语句中,仅在某些个特殊场景提前进入;
break [n]:跳出当前循环
用于条件语句中
    例如:查看用户登录    
    #!/bin/bash
    #
    read -p "Plz enter a username: " userName
    while true; do
        if who | grep "\<$userName\>" &> /dev/null; then
            break
        fi
        echo "not here."
        sleep 5
    done
    echo "$userName is logged on."
    #!/bin/bash
    #
    read -p "Plz enter a username: " userName
    until who | grep "\<$userName\>" &> /dev/null; do
      sleep 5
      echo "not here"
    done
    echo "here"本文出自 “hanye” 博客,请务必保留此出处http://9025736.blog.51cto.com/9015736/1565723
标签:接触shell
原文地址:http://9025736.blog.51cto.com/9015736/1565723