ソースコード・リテラシーのススメ

第20回 ソフトウェア・ツールズの活用[応用編]

この記事を読むのに必要な時間:およそ 3 分

updatepkgコマンドの作成

前述の通り,パッケージ名は'-'(ハイフン)で区切られた4つの部分から構成されており,パッケージのベース名はその最初の部分になるので,パッケージ名からベース名を取り出すにはcutコマンドを使えばいいでしょう。ベース名のファイルが/var/log/packages/ディレクトリにあるかどうかはfindコマンドを使ってもいいですが,再帰的に調べる必要があるわけでもないので,lsコマンドとgrepコマンドを組み合わせる程度でいいでしょう。

まず最初に作ってみたのはパッケージ名からベース名を取り出し,そのベース名が/var/log/packages/以下にあるかどうかを調べるスクリプトです。

 1  #!/bin/sh
 2  pkg=$1
 3  base=`echo $pkg | cut -f1 -d'-'`
 4  chk=`ls /var/log/packages/* | grep $base`
 5  if [ "$chk.x" != ".x"  ]; then
 6      echo "removepkg $base"
 7  fi
 8  echo "installpkg $pkg"

このスクリプトでは,

2行目で$pkgという変数に1つめの引数$1で指定したパッケージ名を入れ,
3行目で$pkgからcutを使ってパッケージのベース名を取り出して$base変数に代入し,
4行目で/var/log/packages/ディレクトリの全ファイルから$baseをgrepした結果を$chkという変数に代入して,
5行目で$chk変数に何か文字列が入っているかを調べ,⁠何か文字列が入っていればダブルクォートで展開した結果は.xとは異なる)入っていればgrep $baseで文字列が検出されている(=そのパッケージはインストールされている)から,まずそのパッケージを
6行目のremovepkgでアンインストールしてから,
8行目のinstallpkgで指定されたパッケージをインストールする,

という流れになっています。

なお,このスクリプトでは動作テストのために6行目と8行目はremovepkgやinstallpkgコマンドを実際には実行せずechoで実行すべきコマンドラインを出力させています。

アップデートするパッケージが1つだけならこのスクリプトでも動きそうですが,updatepkgコマンドを使いたいのは複数のパッケージをまとめてアップデートする際なので,複数のパッケージを指定できるようにした方がいいでしょう。多数の引数を指定できるようにfor文でループを回すようにしてみます。

 1  #!/bin/sh
 2  for pkg in $* ; do 
 3      base=`echo $pkg | cut -f1 -d'-'`
 4      chk=`ls /var/log/packages/* | grep $base`
 5      if [ "$chk.x" != ".x" ]; then
 6          echo "removepkg $base"
 7      fi
 8      echo "installpkg $pkg"
 9  done 

この例では2行目の$*で引数として指定した全てのパッケージを対象にforループで処理を回すようにしています。

このスクリプトを使えば,あるディレクトリの全てのパッケージを対象にupdatepkg *.tgzのような操作が可能になりますが,カレントディレクトリにあるパッケージ以外のパッケージを対象にしようとすると,パス名を含んだパッケージ名の分割がうまく行かず,インストール済みか否かのチェックが機能しません。そこでパッケージ名をパス名付きで指定した場合にも対応するようにしました。

 1  #!/bin/sh
 2  for tmppkg in $* ; do 
 3      pkg=`basename $tmppkg`   
 4      base=`echo $pkg | cut -f1 -d'-'`
 5      chk=`ls /var/log/packages/* | grep $base`
 6      if [ "$chk.x" != ".x" ]; then
 7          echo "removepkg $base"
 8      fi
 9      echo "installpkg $tmppkg" 
10  done

以前は直接$pkgに引数で指定したパッケージ名を代入していましたが,このスクリプトではいったん$tmppkgという名前に受けて,basenameコマンドで$tmppkgのファイル名の部分のみを$pkgに代入して以後の処理を行っています。ただし,installpkgの際には元のパス名を含んだパッケージ名を使う必要があるので,9行目のinstallpkgでは$tmppkgを対象にしています。

このスクリプトでだいたい思ったような動作になりましたが,いろいろ試しているとパッケージのベース名の一部が重なる際(xvはインストールされておらず,xvinfoがインストールされている環境で,xvパッケージをインストールしようとすると,5行目のgrepでxvinfoが引っかかってxvはインストール済みとされremovepkgしようとしてエラーになる⁠⁠,正しく処理ができないようです。grepのチェックをもう少し厳しくしてみましょう。

 1  #!/bin/sh
 2  for tmppkg in $* ; do
 3      pkg=`basename $tmppkg`    
 4      base=`echo $pkg | cut -f1 -d'-'`
 5      chk=`ls /var/log/packages/* | grep "^$base$" ` 
 6      if [ "$chk.x" != ".x" ]; then
 7          echo "removepkg $base"
 8      fi
 9      echo "installpkg $tmppkg"
10  done

5行目のgrepの変更した引数"^$base$"は正規表現を使った指定で,⁠行頭(^)から$baseが出現し,$baseの後には何も無くて行末($)が来る」というパターンにマッチさせています。この指定を使えばxvとrxvtやxvinfo,xvidtuneなどを区別できるでしょう。

とりあえずこの程度で必要な処理は行えそうですが,備忘録代わりにヘルプメッセージを出力する機能を追加しておきましょう。

 1  #!/bin/sh
 2  if [ $#  = 0 ]; then
 3      echo "usage: $0 package(s)" 
 4      exit 
 5  fi
 6  for tmppkg in $* ; do
 7      pkg=`basename $tmppkg`    
 8      base=`echo $pkg | cut -f1 -d'-'`
 9      chk=`ls /var/log/packages/* | grep "^$base$" `
10      if [ "$chk.x" != ".x" ]; then
11          echo "removepkg $base"
12      fi
13      echo "installpkg $tmppkg"
14  done

追加した2行目から4行目の処理は,引数の個数($#)を調べて,引数が指定されていなければusage(使い方)メッセージを表示して終了する,というものです。ここで$0はこのシェルスクリプトの名前に置換されるので,このスクリプトをupdatepkgというコマンドで保存しておけば,その名前に置換されてメッセージが表示されます。

% ./updatepkg 
usage: ./updatepkg package(s)

今回はこのあたりで止めておきますが,このコマンドをテストしていると「指定されたパッケージのバージョンを調べて,インストール済みの方が新しいバージョンならばエラーメッセージを出してインストールを中止する」とか,⁠そのような場合でも-fオプションを指定すれば強制的にインストールできる」といった機能があればより便利そうだ,という気になりました。これらの機能をどう実現するかは宿題ということにしておきましょう。

このようにテストしながら問題点をさっと修正したり,あったら便利と思った機能を簡単に追加したりできるのが,シェルスクリプトの大きな魅力です。また,こうして作った新しいコマンドをパスの通った場所に置けば,システムに用意されているコマンドと同様に利用できるようになり,そのコマンドを下請けに使う新しいコマンド(たとえば,指定したディレクトリ以下のパッケージを全てアップデートするupdatedirコマンド)を作ることも可能です。

筆者の場合,Linux上でソフトウェア・ツールズをあれこれ組み合わせて使ったり,このような自作コマンドを使って作業している時は新しいアイデアがいろいろと湧いてきて「PCを使っている」という気になりますが,Windowsでアプリの指示に従ってあちらこちらをクリッククリックさせられる作業では「PCに使われている」という気になってイライラしてきます。この「自分の意のままにPCを使いこなしている」という麻薬的な感覚が,Linuxから離れられない理由のひとつでしょう。

著者プロフィール

こじまみつひろ

Plamo Linuxとりまとめ役。もともとは人類学的にハッカー文化を研究しようとしていたのが,いつの間にかミイラ取りがミイラになってOSSを仕事にするようになってしまいました。最近はスペシャリスト養成を目的とした専門職大学院で教壇に立ったりもしています。

URLhttp://www.linet.gr.jp/~kojima/Plamo/index.html