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

 

posted @ 2018-04-11 09:10  warren1236  阅读(213)  评论(0编辑  收藏  举报