shell编码整理

从开始接触linux,或多或少会使用到shell,这篇文章用来整理下用过的shell语法,和比较常见的套路。

常用语法

test

  • 用于检查某个条件是否成立,它可以进行数值、字符和文件三个方面的测试

    1
    2
    3
    if test  -e startup.sh ;then 
    等价于
    if [[ -e startup.sh ]];then
  • 注意:可以使用[[]]就不要使用[],[[]]兼容在命令中使用&&、||、<和> 等操作符

数组

  • 定义数组

    1
    modules=(bond-web bifrost model-engine gaeaproxy)
  • 获取数组所有元素,@可被*替换

    1
    ${modules[@]}
  • 遍历数组

    1
    2
    3
    for module in "${modules[@]}"; do
    echo $module
    done
  • 读取数组指定元素

    1
    ${modules[index]}
  • 数组长度

    1
    @可被*替换|${#my_array[@]}

变量

  • 全局变量

    1
    2
    # 全局变量的作用域是当前的进程,而不是前端的shell脚本文件
    a=1
  • 局部变量

    1
    local a=1
  • 环境变量

    1
    2
    export a=1
    作用域为当前shell进程和其子进程
  • 特殊变量

示例 变量含义
$@ 所有入参,可以通过set设置 set 11 22 33 44
$# 参数个数
$? 上个命令的退出状态 函数的返回值
$$ 当前shell进程的ID
$! Shell最后运行的后台Process的PID
total=$#|action=${!total} 获取最后一个参数,也可通过eval action=\$$#

|` `|指令定义,相较于’’,会预执行,在指令嵌套时经常用到|
|echo $aa | echo ${aa}|读取变量|
|$((2+3)) |进行整数运算|

eval

  • 该命令对变量进行两次扫描
    1
    2
    3
    4
    5
    a=`echo hello`
    b='echo $a'
    等价于
    a='echo hello'
    b=eval 'echo $a'

引号

示例 含义
‘ ‘ 单引号 剥夺所有字符的特殊含义,如 n=3;echo ‘$n’ -> $n
“ “ 双引号 引号内可参数替换,$和反引号
反引号 用命令替换,即先执行内命令,将输出结果暂存,在适当的地方输出

重定向

1
ehco 'haha' > /tmp/tmp.log 2>&1

常见的服务启动脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
#!/bin/bash

eval action=\$$#

main() {
case "$module" in
module1)
start_cmd="cmd1"
;;
module2)
start_cmd="cmd2"
;;
*)
echo "usage: $module {module1|module2}"
exit -1
esac
}

all() {
for module in "${modules[@]}"; do
main
echo
echo "[INFO] $module:"
echo "[INFO] processing: ${module} ${action}"
echo "=================="
action
echo "--------------"
done
}

action() {
case "$action" in
start)
start
status
;;
stop)
stop
;;
status)
status
;;
restart)
stop
start
status
;;
*)
echo "usage: $action {start|stop|status|restart}"
exit -1
esac
}

usage() {
echo "usage: $0 {all|[module1, ...]} {start|stop|status|restart}"
}

multiple() {
total=$#
action=${!total}
for (( i=1; i<total; i++)); do
module=${!i//\//}
main
echo "[INFO] $module:${start_cmd}"
echo "[INFO] processing: ${module} ${action}"
echo "=================="
action
echo "--------------"
done
}

getpid() {
if [ ! -d "pids" ]; then
mkdir pids
fi
if [ ! -f "pids/${module}_pid" ];then
echo "" > pids/${module}_pid
fi
module_pid=`cat pids/${module}_pid`

pid=`ps aux | grep ${module_pid} | grep -v grep | grep -v $0 | awk '{print $2}'`

if [[ -n ${pid} ]]; then
return 0
else
return 1
fi
}

status() {
getpid
if [[ -n ${pid} ]]; then
echo "status:
`ps aux | grep ${pid} | grep -v grep`"
return 0
else
echo "service not running"
return 1
fi
}

start() {
getpid
if [[ $? -eq 1 ]]; then
eval $start_cmd
echo $!>pids/${module}_pid
getpid
if [[ $? -eq 0 ]]; then
echo "service start sucessfully. pid: ${pid}"
else
echo "service start failed"
fi
else
echo "service already started. pid: ${pid}"
fi
}

stop() {
getpid
if [[ -n ${pid} ]]; then
echo "killing:
`ps aux | grep ${pid} | grep -v grep`"
kill -9 ${pid} && sleep 0.01
getpid
if [[ $? -eq 1 ]]; then
echo "killed"
else
echo "kill error"
fi
else
echo "service not running"
fi
}

case "$1" in
all)
all $@
;;
usage)
usage
;;
*)
multiple $@
;;
esac
  • 注意服务启动间隔如果不加sleep 0.01,可能会导致获取服务状态异常,即杀掉服务需要一定的信号处理时间

开机启动

  • 将启动指令配置进/etc/rc.d/rc.local
  • 注意,任何一个脚本执行失败,即exit非0,将导致该shell session内的所有启动服务失败,而如何配置在rc.local中的指令exit非0,将导致整个系统初始化失败
-------------The End-------------
坚持原创技术分享,您的支持将鼓励我继续创作!