前回は実用的なシェルスクリプトの例として、
バージョン取得用関数
オープンソースソフトウェア
以前にも紹介したように、
前回紹介したようにPlamo Linuxの場合、
PACKAGE NAME: bash-3.2.39-i386-P1
COMPRESSED PACKAGE SIZE: 1213 K
UNCOMPRESSED PACKAGE SIZE: 2190 K
PACKAGE LOCATION: /var/adm/mount/plamo/00_base/bash-3.2.39-i386-P1.tgz
...
バージョン番号はパッケージ名の一部として PACKAGE NAME: 行に記録されているので、
シェルスクリプトでは、
1 get_version() {
2 local old_name=`cat /var/log/packages/$1 | grep "^PACKAGE NAME" | cut -f2 -d':' `
3 local old_vers=`echo $old_name | cut -f2 -d'-'`
4 echo $old_vers
5 }
2行目と3行目にあるlocalという宣言は、
2行目にある$1は関数に与えた引数の指定で、
パイプの後半ではgrepコマンドで
シェルスクリプトでは、
バージョンチェック用関数
次に、
1 check_vers() {
2 local old=$1
3 local new=$2
4
5 for i in 1 2 3 4 5; do
6 t1=`echo $old | cut -f$i -d'.'`
7 t2=`echo $new | cut -f$i -d'.'`
8 if [ $t2 -gt $t1 ]; then
9 return $t2
10 fi
11 done
12 return 0
13 }
この関数では5行目から11行目のループの部分で、
8行目はシェルのtest 機能([ .. ])を用いて、
x.
一方、
なお、
改訂版スクリプト
それでは、
1 #!/bin/sh
2
3 get_version() {
4 local old_name=`cat /var/log/packages/$1 | grep "^PACKAGE NAME" | cut -f2 -d':' `
5 local old_vers=`echo $old_name | cut -f2 -d'-'`
6 echo $old_vers
7 }
8
9 check_vers() {
10 local old=$1
11 local new=$2
12
13 for i in 1 2 3 4 5; do
14 t1=`echo $old | cut -f$i -d'.'`
15 t2=`echo $new | cut -f$i -d'.'`
16 if [ $t2 -gt $t1 ]; then
17 return $t2
18 fi
19 done
20 return 0
21 }
22
23 if [ $# = 0 ]; then
24 echo "usage: $0 package(s)"
25 exit
26 fi
27 for tmppkg in $* ; do
28 pkg=`basename $tmppkg`
29 base=`echo $pkg | cut -f1 -d'-'`
30 chk=`ls /var/log/packages | grep "^$base$" `
31 if [ "$chk.x" != ".x" ]; then
32 vers=`echo $pkg | cut -f2 -d'-'`
33 old_vers=`get_version $base`
34 check_vers $old_vers $vers
35 ver_test=$?
36 if [ $ver_test != "0" ]; then
37 echo "removepkg $base"
38 else
39 echo "same or newer vesion($chk-$old_vers) has been installed."
40 echo "stop installation for $tmppkg"
41 continue
42 fi
43 fi
44 echo "installpkg $tmppkg"
45 done
3行目から21行目が今回作成した関数です。シェルスクリプトの関数は実行される前に定義しておかないといけないので、
33行目と34、
一方、
36行目からは$ver_
オプション解析機能
いくつかのパッケージで動作テストしてみると、
原因は-gtに代表されるシェルスクリプトの比較演算子が整数の大小を見分ける機能しか持たないことで、
バージョン番号に数字以外が含まれた場合の処理を考えるのは面白いテーマになりそうですが、
1 for opt in $*
2 do
3 case $opt in
4 -f)
5 force_flag=1 ; shift ;;
6 -h)
7 usage ;;
8 esac
9 done
この処理は、
1行目の $* は引数全てを意味し、
完成版スクリプト
オプション解析機能を追加し、
1 #!/bin/sh
2
3 get_version() {
4 local old_name=`cat /var/log/packages/$1 | grep "^PACKAGE NAME" | cut -f2 -d':' `
5 local old_vers=`echo $old_name | cut -f2 -d'-'`
6 echo $old_vers
7 }
8
9 check_vers() {
10 local old=$1
11 local new=$2
12
13 for i in 1 2 3 4 5; do
14 t1=`echo $old | cut -f$i -d'.'`
15 t2=`echo $new | cut -f$i -d'.'`
16 if [ $t2 -gt $t1 ]; then
17 return $t2
18 fi
19 done
20 return 0
21 }
22
23 usage() {
24 echo "usage: $0 [-f] [-h] package(s)"
25 echo " -f force install mode(without version check)"
26 echo " -h help(this message)"
27 exit
28 }
29
30 for opt in $*
31 do
32 case $opt in
33 -f)
34 force_flag=1 ; shift ;;
35 -h)
36 usage ;;
37 esac
38 done
39
40 if [ $# = 0 ]; then
41 usage
42 fi
43
44 for tmppkg in $* ; do
45 pkg=`basename $tmppkg`
46 base=`echo $pkg | cut -f1 -d'-'`
47 vers=`echo $pkg | cut -f2 -d'-'`
48 chk=`ls /var/log/packages | grep "^$base$" `
49 if [ "$chk.x" != ".x" ]; then
50 if [ "$force_flag.x" != ".x" ]; then
51 /sbin/removepkg $base
52 else
53 old_vers=`get_version $base`
54 check_vers $old_vers $vers
55 ver_test=$?
56 if [ $ver_test != "0" ]; then
57 /sbin/removepkg $base
58 else
59 echo "same or newer vesion($chk-$old_vers) has been installed."
60 echo "installation stopped for $tmppkg"
61 continue
62 fi
63 fi
64 fi
65 /sbin/installpkg $tmppkg
66 done
23から28行目が、
30から38行目がオプションの解析部分で、
40から42行目は-fオプションを除いても引数
パッケージをインストールする44行目からのループでは、
数字以外が含まれた際のバージョンチェックやパッケージごとの強制インストールの有無など、
今回はシェルスクリプトを作っていく過程を順を追って紹介しました。たいていのソースコードは、
本連載で紹介してきた文書の読み方同様、