一,Shell中特殊且重要的变量
$0结合dirname和basename分别取出脚本名称和脚本路径
[root@192-168-3-163 scripts]# cat test.sh #!/bin/bash dirname $0 basename $0 [root@192-168-3-163 scripts]# sh /mnt/scripts/test.sh /mnt/scripts test.sh
也可参考系统rpcbind脚本
echo $"Usage: $0 {start stop | status | restart | reload }"
$n测试
[root@192-168-3-163 mnt]# cat test.sh echo $1 $2 $3 $4 $5 $6 $7 $8 $9 $10 $11 $12 $13 $14 $15 [root@192-168-3-163 mnt]# sh test.sh 1 5 6 #传入3个参数,结果显示有误 1 5 6 10 11 12 13 14 15 [root@192-168-3-163 mnt]# cat test.sh #$9以上的参数用大括号括起来结果输出正常 echo $1 $2 $3 $4 $5 $6 $7 $8 $9 ${10} ${11} ${12} ${13} ${14} ${15} [root@192-168-3-163 mnt]# sh test.sh 1 5 6 1 5 6
脚本参考案例
case "$1" in start) if [ -f $PIDFILE ] then echo "$PIDFILE exists, process is already running or crashed" else echo "Starting Redis server..." $EXEC $CONF fi ;; stop) if [ ! -f $PIDFILE ] then echo "$PIDFILE does not exist, process is not running" else PID=$(cat $PIDFILE) echo "Stopping ..." $CLIEXEC -p $REDISPORT shutdown while [ -x /proc/${PID} ] do echo "Waiting for Redis to shutdown ..." sleep 1 done
$# 特殊变量获取脚本传参个数的实践
[root@192-168-3-163 scripts]# cat test.sh #!/bin/bash echo $1 $2 $3 $4 $5 echo $# [root@192-168-3-163 scripts]# sh test.sh {1..10} #传入10个参数 1 2 3 4 5 #接收5个 10 #打印参数总数10个
范例
[root@192-168-3-163 scripts]# cat test.sh #!/bin/bash [ $# -ne 2 ] && { #如果执行脚本参数的个数不等于2 echo "must be two args" exit 1 #给出上面提示 退出 } echo Beijing #满足参数要求后 打印
if判断写法
[root@192-168-3-163 scripts]# cat test.sh #!/bin/bash if [ $# -ne 2 ] #如果参数不等于2 then echo "USAGE:/bin/sh $0 arg1 arg2" #如果不满足参数提示用法 exit 1 fi echo $1 $2
$*和$@特殊变量功能及区别说明
范例 利用set设置位置参数(同命令行脚本的传参)
[root@192-168-3-163 scripts]# set -- "I am" handsome boy [root@192-168-3-163 scripts]# echo $# #输出参数个数 3 [root@192-168-3-163 scripts]# echo $1 I am [root@192-168-3-163 scripts]# echo $2 handsome [root@192-168-3-163 scripts]# echo $3 boy [root@192-168-3-163 scripts]#
测试$*和$@,注意此时不带双引号
[root@192-168-3-163 scripts]# set -- "I am" handsome boy [root@192-168-3-163 scripts]# echo $* I am handsome boy [root@192-168-3-163 scripts]# echo $@ I am handsome boy [root@192-168-3-163 scripts]# for i in $*; do echo $i; done I am handsome boy [root@192-168-3-163 scripts]# for i in $@; do echo $i; done I am handsome boy #上面测试结果相同
测试“$*” 和“$@”,注意,此时带有双引号:
[root@192-168-3-163 scripts]# set -- "I am" handsome boy [root@192-168-3-163 scripts]# echo "$*" I am handsome boy [root@192-168-3-163 scripts]# echo "$@" I am handsome boy [root@192-168-3-163 scripts]# for i in "$*";do echo $i;done #当做一个参数输出 I am handsome boy [root@192-168-3-163 scripts]# for i in "$@";do echo $i;done I am handsome boy #每个参数均独立输出
Shell进程中的特殊状态变量
$? 获取执行上一个指令的执行状态返回值(0为成功,非零为失败) $$ 获取当前执行的Shell脚本的进程(PID) $! 获取上一个在后台工作的进程的进程号(PID) $_ 获取在此之前执行的命令或脚本的最后一个参数
在企业场景下,“$?” 返回值的用法如下:
1.判断命令、脚本或函数等程序是否执行成功
2.若在脚本中调用执行“exit 数字”,则会返回这个数字给“$?”变量
3.如果是在函数里,则通过“return数字” 把这个数字以函数返回值的形式传给“$?”
stop() { echo -n $"Stopping $prog: " killproc $prog #这个是停止rpcbind的命令 RETVAL=$? #将上述命令的返回值"$?" 赋值给RETVAL变量,用于后面的判断 echo [ $RETVAL -eq 0 ] && { #这里判断,如果返回0,执行下面指令 rm -f /var/lock/subsys/$prog rm -f /var/run/rpcbind* } return $RETVAL #如果返回值不等于0,则跳过条件表达式判断,在这里直接作为返回值传给执行stop函数的脚本 }
$$特殊变量功能及实践
[root@192-168-3-163 scripts]# more test.sh #!/bin/bash echo $$ > /tmp/a.pid #把进程id写入到文件 sleep 300 [root@192-168-3-163 scripts]# sh test.sh & [1] 11485 [root@192-168-3-163 scripts]# cat /tmp/a.pid 11485
范例
[root@192-168-3-163 scripts]# cat test.sh #!/bin/bash pidpath=/tmp/a.pid #定义pid文件 if [ -f "$pidpath" ] #如果存在,执行下面then语句 then kill -9 `cat $pidpath` > /dev/null 2>&1 #杀掉与前一个进程号对应的进程 rm -f $pidpath fi echo $$ > $pidpath sleep 300 [root@192-168-3-163 scripts]# sh test.sh & [3] 12654 [2]- Killed sh test.sh [root@192-168-3-163 scripts]# sh test.sh & [4] 12668 [3]- Killed sh test.sh [root@192-168-3-163 scripts]# ps aux |grep test.sh |grep -v grep root 12668 0.0 0.0 113128 1408 pts/1 S 16:50 0:00 sh test.sh #无论运行多少此脚本,都只有一个进程
*提示:这个是一个生产案例的简单模拟,脚本用于执行启动或者定时任务时,相同的脚本中只能有一个运行,当新脚本运行时,必须关闭未运行完成或未退出的上一次的同名脚本进程
内置变量命令
echo -n 不换行输出内容 -e 解析转义字符(如下面的字符) 换行 回车 制表符 退格 v 纵向制表符
范例
[root@192-168-3-163 scripts]# echo beijing;echo shanghai beijing shanghai [root@192-168-3-163 scripts]# echo -n beijing;echo shanghai beijingshanghai [root@192-168-3-163 scripts]# echo "beijing shanghai nanjing hangzhou" beijing shanghai nanjing hangzhou [root@192-168-3-163 scripts]# echo -e "beijing shanghai nanjing hangzhou" beijing shanghai nanjing hangzhou
exec使用
命令格式:exec命令参数
功能:exec 命令能够在不创建新的子进程的前提下,转去执行指定的命令,当指定的命令执行完毕后,改进程(也就是最初的Shell)就终止了。
当使用exec 打开文件后,read命令每次都会将文件指针移动到文件的下一行进行读取,直到文件末尾,利用这个可以实现处理文件内容。
范例:
[root@192-168-3-163 ~]# cat /tmp/tmp.log 1 2 3 4 5 [root@192-168-3-163 ~]# cat exec.sh #!/bin/bash exec < /tmp/tmp.log while read line do echo $line done echo ok [root@192-168-3-163 ~]# sh exec.sh 1 2 3 4 5 ok
shift 命令使用
[root@192-168-3-163 scripts]# cat test.sh #!/bin/bash echo $1 $2 if [ $# -eq 2 ] then shift echo $1 fi [root@192-168-3-163 scripts]# sh test.sh 1 2 1 2 2
应用场景:当我们写Shell希望像命令行的命令通过参数控制不同的功能时,就会先传一个类似-c的参数,然后再接内容。
[root@192-168-3-163 scripts]# cat test.sh #!/bin/bash echo $1 $2 if [ $# -eq 2 ] then shift echo $1 fi [root@192-168-3-163 scripts]# sh test.sh 1 2 1 2 2 [root@192-168-3-163 scripts]# sh test.sh -c 1 -c 1 1
可以参考ssh-copy-id -i /root/.ssh/id_dsa.pub
[root@192-168-3-163 scripts]# sed -n '105,122p' /usr/bin/ssh-copy-id case "$1" in -i?*|-o?*|-p?*) OPT="$(printf -- "$1"|cut -c1-2)" OPTARG="$(printf -- "$1"|cut -c3-)" shift ;; -o|-p) OPT="$1" OPTARG="$2" shift 2 ;; -i) OPT="$1" test "$#" -le 2 || expr "$2" : "[-]" >/dev/null || { OPTARG="$2" shift } shift
作用:方便
有关set和eval命令的使用案例(特殊位置的变量用法)参考http://oldboy.blog.51cto.com/2561410/1175971