SCMLife.com

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 4089|回复: 0

[Shell] 说说Shell在代码重构中的应用

[复制链接]
发表于 2012-7-11 01:32:08 | 显示全部楼层 |阅读模式
本帖最后由 技术狂人 于 2012-7-11 01:35 编辑 ( j- S0 U1 [, ~* D

3 \7 |9 v- g1 L) B$ D

代码重构(Code refactoring)有时是很枯燥的,字符串替换之类的操作不仅乏味,而且还容易出错,好在有一些工具可用,以PHP为例,如:RephactorScisr等等,不过现成的工具往往意味着不够灵活,所以今天我要说说Shell在代码重构中的应用。

先来个简单的,假设我们要把PHP文件中的foo_bar全都替换成fooBar,那么可以如下:

方法一,使用Sed:  n/ Y8 B* W# U

  1. shell> find /path -name "*.php" | xargs sed 's/foo_bar/fooBar/g'
复制代码

方法二,使用AWK:

  1. shell> find /path -name "*.php" | xargs awk '{ gsub(/foo_bar/, "fooBar"); print; }'
复制代码

注:为了简单,我把结果直接打印到终端屏幕了,至于如何保存,稍后会说明。

接着说个复杂的:假设某个PHP项目,以前使用类之前必须调用一个名为“includeClass”的方法,现在改用类自动加载的方式,所以要删除硬编码的includeClass调用,出于美观的考虑,如果includeClass下面一行是空行的话,也一起删除,同时考虑大小写不敏感的因素。

重构前的代码示例:

  1. 01 <?php9 Y# a' A5 S6 t) M' u" f& H
  2. 02 includeClass('...');/ H4 T8 z1 t5 k. L2 J3 L
  3. 03 echo 'a';) n* ~( U( d& _3 \' S; O' B4 h
  4. 04
    ' @4 f5 T$ H0 r9 H* v  v
  5. 05 echo 'b';  q( N& u2 _- Z. p
  6. 06 includeClass('...');
    0 f+ n3 t' Y" W# s. R' y
  7. 07 includeClass('...');
    9 \* B* ~$ ^" W. I# V
  8. 08
    5 c( z# h1 B- E8 w
  9. 09
    ! N, j/ Q8 k' `) k9 {6 m1 X' T
  10. 10 echo 'c';2 n: Z9 g. J, N7 w/ u1 M
  11. 11& h) r. S' \+ }) @+ V: d
  12. 12 echo 'd';
    3 H' ?4 ?: P: |7 G. Q% S$ {
  13. 13 includeClass('...');6 L$ F' o6 u" Q) I5 i# }. f# @" \
  14. 14
    : C- H) X, T  _9 }7 e  @8 ~4 u% g
  15. 15
    : A/ u0 u! ]' p9 `+ }$ b
  16. 16 echo 'e';9 x9 U7 Y  `# ~! I: t% D
  17. 17 ?>
复制代码

重构后的代码示例:

  1. 01 <?php/ p5 d3 [) s6 @$ S
  2. 02 echo 'a';
    : M  z3 F6 @+ `7 A9 c
  3. 03; I+ z4 ?) h7 K. B7 f% P
  4. 04 echo 'b';
    # @/ U& i2 V& @/ Z2 n
  5. 05
    3 J/ P4 G; K2 J  U( b
  6. 06 echo 'c';
    , z! p9 B3 g9 z0 h9 Y2 `
  7. 074 {% {2 Y1 q+ x" X
  8. 08 echo 'd';5 R9 B% _+ x9 H, _* z2 Z+ s
  9. 09
    0 l# q: A: L+ J& n
  10. 10 echo 'e';
    / t  m# _( T" d+ O+ l
  11. 11 ?>
复制代码

在动手前,我们需要先摸摸底,了解一下大概的情况:

  1. shell> grep -I -ri includeClass /path | more
复制代码

其中,grep命令的参数乍一看不好记,不过只要按照我说的方法记,就永远不会忘:前面的参数看做英文,后面的参数看做拼音。至于参数的具体含义,请参阅man文档

方法一,使用Sed编写脚本script.sh:

  1. #!/bin/sh
    , P) t1 q: f1 g
  2. 6 K+ R# }, K- |. W3 k, l% H% k
  3. for PHP in $@; do
    + i: P. t8 R; _4 b! v0 s1 g
  4.     /bin/sed -i '
    . L$ B8 U/ |+ |
  5.         /includeClass/I {. r$ U* `9 i: N5 v
  6.             h
    8 [5 Y: f: c* n6 I& e
  7.             d
    + d& w: s8 }, [: f# t
  8.         }+ [) I4 A( }7 |2 [" i$ S6 Z
  9. 5 m& W* x2 f0 }( o  ?
  10.         /^$/ {7 A2 t  Y9 [  `, M! J6 K
  11.             x: q/ M7 Q7 z8 o+ k; i
  12.             /includeClass/Id' B4 Y  z' A  u9 d8 @) r
  13.             x; W& w5 v+ ]/ D5 d' R- \
  14.         }6 f" i) n# s) N4 X6 V7 ?* Q
  15. ( |- L- R% T6 @1 [: J! @
  16.         h
    * e& |! }7 _' \9 [" p+ |+ e  u2 N8 \
  17.     ' $PHP' S' u4 ^' M2 F
  18. done
复制代码

注:篇幅所限,我把正则写的比较简单

Sed的缺点是代码可读性比较差,优点是代码较短。另外内置的“-i”选项可以直接完成保存,这是我喜欢Sed的原因之一。

方法二,使用AWK编写脚本script.sh:

  1. #!/bin/sh
    8 a6 \5 I$ n" a
  2. 1 C# x& d) p6 Z8 `
  3. for PHP in $@; do& l7 V* }/ C& X6 m
  4.     TMP=$(mktemp)
    2 z( [! ]6 q* \4 }; E8 u
  5. 8 \3 B+ D+ n2 e1 Q' d0 a- o- }
  6.     /bin/awk '
    # B4 J3 k  X1 d$ `6 R
  7.         BEGIN {
    ' A# V6 I+ i! t
  8.             IGNORECASE = 1
    : l2 g" b( H. {8 J  w7 p  z
  9.         }& Z& L; j, ^, o& n$ O2 [

  10. ) @/ l0 w* z5 M; T1 ?0 ^
  11.         /includeClass/ {5 O  U3 q9 y% |
  12.             previous = $0
    0 j0 u* g9 ?$ x- i& e
  13.             next7 U+ K1 C0 X3 ]3 Q( Y5 {0 J" {
  14.         }, Q( }% K3 I  B8 p
  15. ( m+ _) O5 Q4 p" K: ]& @" r
  16.         /^$/ {
    + J$ n8 J. K  u$ y; P  `7 n
  17.             if (previous ~ /includeClass/) {" M+ B" |. Y2 A; T3 I$ g
  18.                 previous = $0$ k' g! J  j  l
  19.                 next- ^& T8 g+ h7 W6 k+ j5 @; Z, |
  20.             }- y9 K! V+ U3 U: ?' ?8 O; A
  21.         }7 o" n# h8 F( \$ }$ L) g( n6 W
  22. , L, b4 x1 L$ i, B* g" g* }$ o% N
  23.         {
    % F" C! t9 W( _- K* L+ x2 V9 y  e# t
  24.             previous = $0
    . L9 g2 {0 _. _5 s
  25.             print
    , f5 P: E6 q2 x% f) l+ V7 @
  26.         }
    ; C+ C8 n( O8 _. T) g9 U; X+ Z9 ~/ s) \
  27.     ' $PHP > $TMP
    # ]  l4 s. {# D  K; r9 B/ ^

  28. + n  ~' W# E6 `/ o& f
  29.     /bin/cp -f $TMP $PHP% D* D% W& B9 p8 ^" n# Z. I% u. ?
  30.     /bin/rm -f $TMP; w' h3 M7 b) d9 k
  31. done
复制代码

注:篇幅所限,我把正则写的比较简单

AWK的缺点是代码比较长,优点是代码可读性较好。另外程序中是通过生成一个唯一的临时文件来完成保存的。

提醒:直接覆盖原始文件有时候并不合适,毕竟可能有没考虑周详的地方,使用SVN的话就不会有这样的顾虑了,因为即便覆盖了原始文件,也可以在提交前通过“svn diff”命令来检查对错,就算是提交了,也可以恢复到以前的版本。

如果调用script.sh脚本呢?这里给个最一般的例子:

  1. shell> find /path -name "*.php" | xargs /path/to/script.sh
复制代码

简单的任务用Sed写很合适,复杂的任务则最好用AWK写,实战是学习的最好方法,具体可以参考Sed One LineAWK One Line等资料。

说明:本文用到的Sed和AWK均指GNU版本。

; t4 t" x9 l8 q
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

SCMLife推荐上一条 /5 下一条

QQ|小黑屋|手机版|无图版|SCMLife.com ( 京ICP备06056490号-1 )

GMT+8, 2020-2-29 08:38 , Processed in 0.071099 second(s), 8 queries , Gzip On, MemCache On.

Powered by SCMLife X3.4 Licensed

© 2001-2017 JoyShare.

快速回复 返回顶部 返回列表