SCMLife.com

 找回密码
 立即注册

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 3994|回复: 0

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

[复制链接]
发表于 2012-7-11 01:32:08 | 显示全部楼层 |阅读模式
本帖最后由 技术狂人 于 2012-7-11 01:35 编辑
. Q6 D$ o! [4 S" {5 l: r( M6 D
- B- G0 F6 n, Y$ q% [! |; K

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

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

方法一,使用Sed:
0 m5 ?) B" k5 Z4 j4 v7 X

  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 <?php
    ! t% h( r/ l, [' c' R
  2. 02 includeClass('...');
    3 f4 a* \# N  V1 k" C
  3. 03 echo 'a';
    & J- V6 m7 c# ]0 W: j( Q$ p
  4. 04
    - [6 T5 x: H  H$ r1 ~
  5. 05 echo 'b';5 a% z/ f  q$ S0 x
  6. 06 includeClass('...');0 D! V% a3 w- u) [1 S
  7. 07 includeClass('...');
    5 l, P) m0 B# \, [$ V% q0 o, e) _* l
  8. 08/ p2 D' y$ L: Z* g' o4 i# V
  9. 09, i/ i  r! D0 e; D4 s
  10. 10 echo 'c';
    : p3 ]% B! U  y# g+ |" x0 f: v
  11. 11
    % q; B: |; c( T2 N8 h9 I' W$ B, ?$ A
  12. 12 echo 'd';
    ! f! d0 z! o) o, s5 Y; |1 F
  13. 13 includeClass('...');
    ) x, e! |2 y1 j0 E6 T0 s7 S/ D
  14. 14
    ) d3 Z4 }5 s5 h& s
  15. 158 X& L6 u$ ~0 \- |# w* H
  16. 16 echo 'e';
    # h9 e- S' t2 X7 b0 d# v9 r: n
  17. 17 ?>
复制代码

重构后的代码示例:

  1. 01 <?php
    / F4 s3 B, U+ D: r6 \( I4 j6 C
  2. 02 echo 'a';- _" m1 M2 ^# V2 |9 F
  3. 03- t2 s. [+ c; [
  4. 04 echo 'b';
    ) r, \8 ?9 W# m& R" S9 @' G' f! i3 ?
  5. 05
    ! [3 P9 ]$ w  K1 v( p; x7 t. k: _
  6. 06 echo 'c';
    # D7 h6 ~6 m! C1 b" Q$ y# E
  7. 07+ _. y9 I/ ~* q7 H$ v+ O- c
  8. 08 echo 'd';1 d$ E7 g% \) j8 v# M4 d0 K
  9. 09$ N. v9 F  o" F- s1 m, W
  10. 10 echo 'e';
    0 n# K' o" B, N9 z
  11. 11 ?>
复制代码

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

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

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

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

  1. #!/bin/sh, z% v8 Y6 f) d2 W
  2. # y7 w' B3 B6 l# p  V) O2 g
  3. for PHP in $@; do6 C- _: B, V. b5 Q. F- s
  4.     /bin/sed -i ', w! a& Z8 L" e4 @; e, w$ M
  5.         /includeClass/I {
    & R" D# M7 t% ^: b) J8 {
  6.             h! N6 P2 B7 g9 D1 u$ m3 {7 f
  7.             d6 R( c/ s4 V4 J0 Y! w% A3 J
  8.         }% W: a3 L) z% C5 F7 [2 a0 ^
  9. ) G3 O0 r3 j/ ~1 i+ d/ z
  10.         /^$/ {; o! V6 l6 l- i& r% ~% Y
  11.             x6 m% t# @* e) q- Z5 K
  12.             /includeClass/Id
    ( L8 R' e  n% j' V( ]
  13.             x; \9 c, X1 I+ \# W% z, y
  14.         }0 r6 D4 m! G  v2 r; b1 U
  15. $ A6 h" z3 m8 P7 E: M9 ^, p* ^
  16.         h2 }- A% w! A) J- w' ?
  17.     ' $PHP2 U  f5 M( ]& ~1 y
  18. done
复制代码

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

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

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

  1. #!/bin/sh
    ; S5 l5 |1 S5 J. w4 Z
  2. 7 K' s( ^) R9 P5 p* U
  3. for PHP in $@; do5 j( V; z' S+ l. U2 B2 G
  4.     TMP=$(mktemp)( B  L) g; D1 X- e/ h3 U) w

  5. 1 @( y; y0 [) [; e6 D8 M
  6.     /bin/awk ') c5 v  m# D- `. g+ _
  7.         BEGIN {
    4 T, i/ @/ h% {( `
  8.             IGNORECASE = 1
    . ?5 R1 Y; ^4 \4 F7 x) i: K
  9.         }( W  V% z# H$ p4 m

  10. * r! [/ }& y+ G+ P4 l5 |
  11.         /includeClass/ {
    & w. ~, X/ U' G
  12.             previous = $0
    2 n- N. [( F, W, J, W. X! X( o
  13.             next
      q2 O& N5 b# _) X4 H# H
  14.         }* Y! L. O6 N. p6 T# o+ P" j
  15. # S+ ]2 h6 j5 S# d; z$ r
  16.         /^$/ {1 |9 m' n! |% K* @2 R
  17.             if (previous ~ /includeClass/) {& p$ |5 R- s& W# p
  18.                 previous = $0
    ( V; N6 k$ C! O- z' a* H1 u
  19.                 next' _; _6 h, x& T, f* Z
  20.             }. k7 q- p. u/ {" P1 G
  21.         }( i& e4 q6 Q" F$ j" @! {0 O3 b+ s

  22. : A3 N4 T5 Y2 g4 n3 ]* S* G2 F
  23.         {7 K! H* W# S7 T! N0 R" [. U
  24.             previous = $0
    9 ?; w6 y- R, f  D
  25.             print
      D3 \9 z- U' J( ?0 Z2 ]4 b
  26.         }- s3 @; _! V! M/ n4 B
  27.     ' $PHP > $TMP0 r% E2 r, Q# D4 Q8 x# q

  28. 8 q- P! x/ t. d$ h; x
  29.     /bin/cp -f $TMP $PHP+ l, Q% H% n) x( X
  30.     /bin/rm -f $TMP; q" D" u1 l% P) k7 F
  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版本。

2 k8 s$ A) q0 y4 N8 F5 T% `
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

SCMLife推荐上一条 /4 下一条

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

GMT+8, 2019-10-15 15:29 , Processed in 0.065686 second(s), 8 queries , Gzip On, MemCache On.

Powered by SCMLife X3.4 Licensed

© 2001-2017 JoyShare.

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