Shell变量知识进阶
一,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 解析转义字符(如下面的字符) \n 换行 \r 回车 \t 制表符 \b 退格 \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\tshanghai\nnanjing\thangzhou" beijing\tshanghai\nnanjing\thangzhou [root@192-168-3-163 scripts]# echo -e "beijing\tshanghai\nnanjing\thangzhou" 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
志不强者智不达
浙公网安备 33010602011771号