MIRACLE
メールサービス申込 ユーザー登録 パートナー情報
お問い合わせ FAQ サイトマップ
MIRACLE LINUXの特長 製品紹介 サービス案内 購入 サポート 技術フォーラム

プロフィール

コアテクノロジー部

ミラクル・リナックスのOS開発やサポートを担う、技術部の精鋭陣が交代で担当します。

ミラクル関連リンク

採用情報

サイト検索

2009年10月

        1 2 3
4 5 6 7 8 9 10
11 12 13 14 15 16 17
18 19 20 21 22 23 24
25 26 27 28 29 30 31

« 自宅サーバクラッシュ | メイン | LX-2010にMIRACLE LINUX V4.0をインストール »

すべての道はUNIXに通ず?

こんにちは。二卵性双生児(男女)AB 型というなかなかレアな出生歴を持つ kyagiです。カードダースのキャラだったらプレミアものになっていたかもしれません。現実の人生は平凡そのものを歩んでいます。

最近シェルスクリプト内でのラッパ化(wrapper)を行う機会があったのですがそこでちょっとした落し穴にハマッてしまいました。今回はその落し穴についてのお話と最後に小咄をひとつ。

現在のコマンドを表示かつ終了ステータスのチェックを行うために下記のようなexecute() というラッパ関数を作成したのですが、これだと実行するコマンドラインにパイプ「|」やリダイレクト「>」がまじるとエラーになってしまいます。

#!/bin/sh

execute ()
{
        echo "Executing $command"
        $command
        if [ $? -ne 0 ]; then
                echo "ERROR: $command"
                exit 1
        fi
}

# OK
command='ls'
execute

# NG
command='ls -l | awk "{print $NF}"'
execute

# NG
command='echo "hello" >> outputfile'
execute

どうしたものかと 30分考えた挙句、 bash の eval という機能を思いだしました。evalは受け取った引数を結合してコマンドラインとして実行してくれます。すると、これがどうやらビンゴ!だったみたいでうまくいくようになりました。

$ diff a.sh b.sh
6c6
<       $command
---
>       eval $command
[kyagi@dhcp-0234 labo]$

ラッパ化の話はこれで終わりですが最後に雑談系の小咄をもうひとつ。

UNIXにみる世代間の断絶という興味深い記事がありますが、ふと世代別でプログラムの書き方はどう異なってくるのかと思いました。ここではkyagiが独断と偏見のもとシェルスクリプトのループ(0から9までを出力する)の書き方を、世代別でカテゴリ化してみます。

・旧人類(古き良き expr を使う)

$ i=0; while [ $i -lt 10 ]; do echo $i; i=`expr $i + 1`; done

・新人類と旧人類の中間(expr から let に移行)

$ i=0; while [ $i -lt 10 ]; do echo $i; let i=$i+1; done

・新人類(算術式展開を使う)

$ for ((i=0;i<10;i++)); do echo $i; done

・変人(タイプ数が少ないのがイチバン!)

$ for i in `seq 0 9`; do echo $i;done

いかがだったでしょうか。

上司や同僚の世代やTPOにあわせて書き方を変えてみると、世代間のギャップを埋めるのに役立つかもしれません。:-)

トラックバック

このページのトラックバックURL:
http://www.typepad.jp/t/trackback/4447/6604998

このページへのトラックバック一覧 すべての道はUNIXに通ず?:

» イマドキ?のシェルスクリプト トラックバック iTakahiro's D
すべての道はUNIXに通ず? http://blog.miraclelinux.com/ctd/2006/10/post_8433.html 後半で紹介されてるスクリプトは、世代間というよりは、Linux しか使わない人とそれ以外の UNIX系OS も使う人との違いではないかと。 let や (()) での算術式評価は bash の機能なんじゃないのかしら。 この記事 http://www.atmarkit.co.jp/flinux/rensai/sh... [続きを読む]

コメント

基本、旧人類のようです。
変人のseq の部分を 1 2 3 4 5 6 7 8 9 10 とベタで書くこともあるかな。
「UNIXにみる世代間の断絶」の内容は興味深いですな。

世代間の断絶を最も実感できるのはペアプログラミングでしょうか。ギャップは逆に色々吸収できるチャンスでもありますね。

・bash系新人類

bash3 -c 'for i in {0..9}; do echo $i; done'

hirose31さん、コメントありがとうございます。

bash3ではperlのような N..Mといった書き方が使用可能なのですね。勉強になります。:-)

シェルで変数展開する場合、ダブルクォートで括るかどうか検討する癖をつけましょう。多くの場合、つけるべきです(私見。…といったようなこと社内メーリングリストで投げたような :-p)

$ touch blah-blah
$ command='echo "foo bar * hoge"'
$ eval "$command"
foo bar * hoge
$ eval $command
foo bar blah-blah hoge

わかりにくい例ですが、後者だとスペースが欠落したり、シェルのメタキャラクタ相当の文字が不意にシェルに解釈されてしまいます。

先のコメントですが、複数のスペースが表示上はスペース 1つになってしまう…。ということで、コピー&ペーストして試してみてください。

以下、おまけ。
bash 依存が嫌、seq もない環境で、ループの度に expr などの fork/exec をせずに 100 回ループする:

$ tr '\0' '\n' |head -n 100 \
|cat -n \
|while read i; do echo "$i";done

ただの思いつきネタなので、実用的かどうかはわかりません :-)。0 から 99 とかできないし。

fumiyas師匠、コメントありがとうございます。

ダブルクォートでの変数展開は確かに以前社内MLで流れていました。脊髄反射レベルになるまで癖として指に叩き込みます。m(_ _)m

tr からはじまるコマンドラインを打ってみたのですが動作しません。tr の引数にファイルか標準入力が必要でしょうか?

いちいち考えるのが大変なら「クォートしなければならない」として理由がなければ何も考えずにダブルクォートしてしまえば楽ですよ。

tr ですが、/dev/zero を食べさせてあげてください。コピー & ペーストしたときに抜けたか、TypePad が捨てたのかな?

tr で直に /dev/zero を読むとEOFが返ってこないため、はじめはcatにしたらうまくいきました。:-)

$ cat /dev/zero | tr '\0' '\n' | head -n 100 | cat -n | while read i; do echo "$i"; done

コメントを投稿

会社情報 採用情報 個人情報保護方針 商標等取り扱い事項 English
Copyright(c)2000-2006 MIRACLE LINUX CORPORATION. All Rights Reserved.