你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

shell脚本写到停不下来

[复制链接]
gaosmile 发布时间:2020-6-23 10:18
平常工作中,你是否感觉shell脚本只是命令的堆砌;很多时候只是为了实现功能而没有好的组织结构;自己的脚本都不想再看一遍;哈哈,我这就教给shell的“葵花宝典“,自此让你的shell脚本有python一样的美感并且极易维护,真的是shell脚本写到停不下来。
现以nginx控制脚本为例,看一下脚本的美容过程:

  1. ; U6 T- U. j2 d# C9 `" \: [
  2. #!/bin/bash
    * C% J" l. B# N
  3. # set命令的奇妙用途留在文章末尾
    ) Y/ T  \# I" W; \
  4. set -eu5 \3 w9 A0 m2 O1 r* h# t: I
  5. # nginx重载配置文件2 F* e9 C/ W+ a7 l$ |
  6. nginx -c /etc/nginx/nginx.conf -t
    $ U- v" G3 ?, ^
  7. kill -HUP `ps auxf | grep -E "nginx:[[:space:]]+master"| awk '{print $2}'`: U- V1 Y9 P4 C3 x3 i. k+ ?% U
复制代码

: s% i& L) M0 R$ G5 \
宝典秘籍之变量抽离
在脚本中,需要依赖外部的配置,比如配置文件位置,监听端口之类的可变参数,编程时,需要将其抽离为变量,为了更好的引用与维护,省去了外部配置变化时,一个个修改带来的麻烦。
  1. <font style="background-color:rgb(255, 255, 255)">
    7 X$ W6 B! r; M! }! K  F- l8 O
  2. #!/bin/bash
    9 X. r6 V/ n3 m4 f% c6 I
  3. # set命令的奇妙用途留在文章末尾/ }; W, c9 i; t) D2 B6 m
  4. set -eu  Q0 z! J( c; I) c" m: B/ G8 }
  5. # nginx配置文件在不同环境中,位置可能不同,所以需要将其抽离成可配置变量,脚本来引用
    7 D7 j# T1 ]- d3 g& l+ L; Q/ T
  6. NGINX_CONFIG_FILE=/etc/nginx/nginx.conf
    1 Y' [; ]6 C) x# }- I! m6 T* U1 q
  7. 2 O' w( o+ u& q/ k0 N4 W
  8. # nginx重载配置文件6 h( k$ K$ T2 Z$ Z: o5 F
  9. nginx -c $NGINX_CONFIG_FILE -t
    ) o( k9 t5 P3 s& h# J
  10. kill -HUP `ps auxf | grep -E "nginx:[[:space:]]+master"| awk '{print $2}'`</font><font style="background-color:rgb(255, 255, 255)">
    ( W# b( B  X( X
  11. </font>
复制代码
宝典秘籍之模块化
运维毕竟不是专业程序员,写脚本时是怎么舒服怎么来,简单讲就是从上到下依次执行,这就导致复用性差,不易维护,解决这问题的关键在于函数化、模块化思想,shell虽然是一种比较简单的语言,但语言基本的逻辑控制、函数功能都有,这就让我们编写高质量shell脚本带了无限可能。接下来就看一下具体例子来感受一下:

  1. * V7 r" F, {' t
  2. # 由于nginx配置文件检查是执行其他操作的第一步,所以我们将其独立成一个单独函数% X+ |5 A; x* B+ u4 K
  3. #!/bin/bash( S3 K2 D( G) f! q- ^
  4. # set命令的奇妙用途留在文章末尾( b. [6 T' [0 U6 z4 K( Z  B
  5. set -eu
    1 `6 {6 e. T/ [3 \/ ^. c% V/ {6 i9 ~, Y
  6. # nginx配置文件在不同环境中,位置可能不同,所以需要将其抽离成可配置变量,脚本来引用% U8 c7 O  l% i5 S) {
  7. NGINX_CONFIG_FILE=/etc/nginx/nginx.conf% x- _/ \9 d( R0 d8 j. F
  8. $ _, ~/ d8 Z; J: Z' ?+ z6 k, o* s
  9. # 抽离配置文件检查为单独的函数
    3 P. |/ R1 y. |7 m. W3 F
  10. config_test() {
    , w, V$ u2 ^  f" ~3 V( Y
  11.     nginx -c $NGINX_CONFIG_FILE -t
    : H3 }5 N& x# v) F, |! Q  @5 l3 A
  12. }
    2 w/ I3 Z# g% ?
  13. get_nginx_master_pid(){
    ! a8 r# E2 @# L% f- T) F# e
  14.     echo `ps auxf | grep -E "nginx:[[:space:]]+master"| awk '{print $2}'`
    , u% `  v5 I8 W  k; h+ `
  15. }: A5 R- B; b4 b( x& A
  16. # 抽离配置重载为独立函数" B( n3 B8 D9 K3 p0 p
  17. reload() {
    1 n2 ]- l+ y! t: Z
  18.     kill -HUP `get_nginx_master_pid`" k: B9 j) Z! k- \" F& u
  19. }
    ) u5 p( c3 T" e( y/ P- P
  20. - b, y% R) E8 q
  21. # nginx重载配置文件
    8 v. l' D2 n* D
  22. config_test
    ! W# ~1 T' u9 x
  23. reload
复制代码
2 k& y% x% F9 B
宝典秘籍之main函数
脚本的可维护性在于脚本的结构的好坏,为了拥有更好的结构,通常需要在脚本中定义入口函数,即main函数,让我在维护脚本时,可以更好的把握脚本的组织架构,找到切入点:
  1. <font style="background-color:rgb(255, 255, 255)"># n% O2 b- m5 B0 l: t
  2. # 由于nginx配置文件检查是执行其他操作的第一步,所以我们将其独立成一个单独函数
    5 H4 c( j. N) ?- Z0 j
  3. #!/bin/bash0 l) G( {5 P* \+ c
  4. # set命令的奇妙用途留在文章末尾2 y- ^0 I- @; T1 o% I6 f
  5. set -eu
    1 T7 Q6 J" E; f& r1 Y1 }
  6. # nginx配置文件在不同环境中,位置可能不同,所以需要将其抽离成可配置变量,脚本来引用) b/ z( _; v0 r
  7. NGINX_CONFIG_FILE=/etc/nginx/nginx.conf
    , M; {4 ]' I0 N+ f$ e9 B' ^5 |8 _0 ], I
  8. + I4 c6 E9 r# d5 b# Z1 G/ T
  9. # 抽离配置文件为单独的函数
    7 c7 @) x5 K! [# K6 w
  10. config_test() {
    " w& T& Z5 u7 B2 ?1 }: n5 [
  11.     nginx -c $NGINX_CONFIG_FILE -t) c+ n5 W+ h0 V  |
  12. }1 P6 R" [3 \# S$ y/ R( v
  13. 7 e; s- L. d4 `+ u' r
  14. get_nginx_master_pid(){
    - s/ L9 P3 t8 p& x/ G8 L# e5 e
  15.     echo `ps auxf | grep -E "nginx:[[:space:]]+master"| awk '{print $2}'`
    # t7 ]9 O- P; E  K5 K8 S
  16. }
    % X. K) d! P; ~! c+ B% G; {
  17. # 抽离配置重载为独立函数1 h* X9 u0 A& \$ t
  18. reload() {
    , a: @; ^4 f; |" W  ^
  19.     kill -HUP `get_nginx_master_pid`- Q& T/ ~5 h( i; n0 g4 x9 F
  20. }' t1 A2 k5 Y( u' F

  21. 5 ~7 ]. V$ {/ c( r' w. ]
  22. # 入口函数
    " q- Q* w1 _- y1 s9 u: a0 h8 N  F2 m
  23. main() {
    * Z  y' C# }3 P* v! L
  24.     config_test# B8 _$ X0 a+ ?4 L" t
  25.     reload( N* N! {. D. T  N2 X( E1 i& s
  26. }8 g- f$ _  q2 b% Z5 z# J

  27. 8 t! S6 y, U  s$ F5 D# w4 A/ Z
  28. # main在此需要获取脚本本身的参数, 故将$@传递给main函数
    ' ^0 h0 c6 s% C, V0 G4 U% ]
  29. main $@</font><font style="background-color:rgb(255, 255, 255)">
    & n1 N/ l$ K' ]' u2 \( d! @* j
  30. </font>
复制代码
宝典秘籍之函数返回值
在其他编程语言,可以通过return获得函数的返回值,但是return语句在shell中含义不同,return命令会使一个函数返回,会返回一个单一的数字参数,而这个数字参数在调用这个函数的脚本是可见的,如果没有指定返回参数,return在默认情况下会返回上一次命令的返回代码。那如何实现类似其他编程语言的return效果呢?可以使用echo命令:
  1. <font style="background-color:rgb(255, 255, 255)">
    8 z, F2 Q) G9 J+ Y2 N3 A  W' X1 X; o
  2. #!/bin/bash
    1 N9 S% z* c( n# F3 a" ?; D
  3. set -eu( b3 b6 T' C- s7 y% N7 i) U
  4. NGINX_CONFIG_FILE=/etc/nginx/nginx.conf2 `+ Z+ ~3 V2 u5 L
  5. # W9 @& a: n" c2 q  N
  6. config_test() {. g& k0 {8 L3 y& d/ |4 M: K
  7.     nginx -c $NGINX_CONFIG_FILE -t8 L+ r. T$ p0 V. {9 D, j
  8. }% i! o- F( F1 j0 h  W
  9. 8 F" t+ u0 _8 ?6 ]
  10. # 在此处直接把nginx的master pid可以通过反引号来获取echo后的值
    + U( f' v/ v: `
  11. get_nginx_master_pid(){- {9 G$ Q7 ?7 Z2 w% x" ]  d
  12.     echo `ps auxf | grep -E "nginx:[[:space:]]+master"| awk '{print $2}'`- A0 ^" n2 Q( w- @& j9 B) |- p
  13. }
    5 y+ C* q, \0 g2 A

  14. 6 R; A5 p+ A0 r4 M. e6 L
  15. reload() {( i" a. N! M. y) q+ N9 ^
  16.     # `get_nginx_master_pid` 获得nginx master pid
    - P2 _& H! r8 x4 w' `- c
  17.     kill -HUP `get_nginx_master_pid`
    0 Z0 g" K0 [/ l7 H
  18. }# i* P+ V: t! E4 ?; `. C4 E% R
  19. ! z) l) q7 h4 M" W$ e: {) _
  20. # 入口函数
    , t: X% U8 `% [9 V/ e
  21. main() {% K; Y. m7 e( y
  22.     config_test
    $ Q! ^$ J6 t1 T+ |6 n8 B
  23.     reload
      S9 \. w2 t6 b) \. {
  24. }& E8 g* d+ Q: }& }( J; ^$ {
  25. 9 I1 w+ ]9 l# \" {
  26. # main在此需要获取脚本本身的参数, 故将$@传递给main函数
    1 p$ M. K2 @6 Z% C5 C& o: B8 a# W
  27. main $@</font><font style="background-color:rgb(255, 255, 255)">" e9 N$ @# M* F- \% T0 ]
  28. </font>
复制代码
宝典秘籍之set命令
bash内置的set命令,可以改变我们脚本的执行行为,让我对脚本的把握和调试更有力,下面说几种常用的set指令,相信你都会喜欢的:
•set -e: bash脚本遇到错误立即退出•set -n: 检查脚本语法但不执行•set -u: 遇到未设置的变量立即退出•set -o pipefail: 控制在管道符执行过程中有错误立即退出•set -x: 分步调试命令
在写脚本时,我们可以直接在脚本开头简写为如下格式:
  1. <font style="background-color:rgb(255, 255, 255)">
    # q5 D4 ^, |% u- E( B
  2. #!/bin/bash3 Z. a0 x! [4 f( S3 V
  3. set -euxo pipefail</font><font style="background-color:rgb(255, 255, 255)">4 I" s* u+ Z* h. `1 t5 x
  4. </font>
复制代码
检查bash脚本的语法时,可以这样写:
  I( o% W" c9 q! y6 V  y; u7 ^- j
  • bash -n main.sh
    8 P4 \3 i7 H$ v
赞 收藏 评论1 发布时间:2020-6-23 10:18

举报

1个回答
desk1983 回答时间:2020-6-23 15:29:54
沙发
  b2 X% v* @4 ]+ v4 l6 O$ q' _8 d非常好的资料,感谢分享非常好的资料,感谢分享非常好的资料,感谢分享非常好的资料,感谢分享
关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版