  BASH Programming - Introduction HOW-TO
  by Mike G mikkey at dynamo.com.ar
  Mon Jul 27 11:47:00 ART 2000
  日本語訳 千旦裕司
  July 2000

  この文書は、初中級のシェルスクリプトのプログラムを始める人の手引書とし
  て書かれています。(タイトルからも分かるように)これは高度な内容を解説し
  た文書ではありません。わたし自身、シェルプログラムのエキスパートではな
  いですし、ましてや達人でもありません。これを書こうと思い立ったのは、そ
  こから自分が多くを学べるだろうと思ったからであり、もしかしたら他人の役
  に立つかもしれないと考えたからです。どんなフィードバックも歓迎します。
  特に、パッチ形式でいただけると嬉しく思います :)
  ______________________________________________________________________

  目次

  1. イントロダクション
     1.1 最新バージョンの入手場所
     1.2 必要事項
     1.3 この文書の使い方

  2. 非常にシンプルなスクリプト
     2.1 伝統の Hello World スクリプト
     2.2 非常にシンプルなバックアップスクリプト

  3. リダイレクトションについて(redirection)
     3.1 理論と簡単なリファレンス
     3.2 サンプル: stdout を file へ
     3.3 サンプル: stderr を file へ
     3.4 サンプル: stdout を stderr へ
     3.5 サンプル: stderr から stdout へ
     3.6 サンプル: stderr と stdout から file へ

  4. パイプ (pipe)
     4.1 何なのか、どこがいいのか
     4.2 サンプル: sed を使った簡単なパイプ処理
     4.3 サンプル: 'ls -l *.txt' の代替コマンド

  5. 変数 (variable)
     5.1 サンプル: 変数を使った Hello World!
     5.2 サンプル: 非常にシンプルなバックアップスクリプト(改良版)
     5.3 ローカル変数

  6. 条件制御(conditionals)
     6.1 セオリー
     6.2 サンプル: if .. then による基本的な条件制御の例
     6.3 サンプル: "if .. then ... else"  を使った基本的な条件制御の例
     6.4 サンプル: 変数を伴った条件制御

  7. for, while, until によるループ
     7.1 For のサンプル
     7.2 C 言語に似た for
     7.3 while のサンプル
     7.4 until のサンプル

  8. 関数(functions)
     8.1 関数のサンプル
     8.2 パラメーターを取る関数のサンプル

  9. ユーザインターフェイス
     9.1 簡単なメニューを作るために select を使う
     9.2 コマンドラインを使ってみる

  10. その他のスクリプト
     10.1 read を使ってユーザの入力を読み込む
     10.2 数値の評価
     10.3 bash を探す
     10.4 プログラムの戻り値を獲得する方法
     10.5 コマンド出力を獲得する方法
     10.6 複数のソースファイル

  11. 参照テーブル
     11.1 文字列比較演算子
     11.2 文字列比較の実例
     11.3 数値演算子
     11.4 数値関係演算子
     11.5 便利なコマンド
        11.5.1 sed (stream editor)
        11.5.2 awk (データファイルやテキストの検索と整形処理)
        11.5.3 grep (検索パターンに合致する行の出力)
        11.5.4 wc (行、語、バイト数を数えます)
        11.5.5 sort (テキストファイル内の行の並べ替え)
        11.5.6 bc (数値計算用のプログラミング言語)
        11.5.7 tput (端末の初期化や terminfo データベースの検索)

  12. いろいろなスクリプト
     12.1 ディレクトリ上の全ファイルにコマンドを適用する方法
     12.2 サンプル: 非常にシンプルなバックアップスクリプト(改良版)
     12.3 ファイル名変更スクリプト
     12.4 ファイル名変更スクリプト(簡易版)

  13. うまくいかない時(デバッグ)
     13.1 bash の呼び出し方

  14. この文書について
     14.1 (無)保証について
     14.2 翻訳について
     14.3 謝辞
     14.4 改訂履歴
     14.5 参考ホームページ
     14.6 日本語訳について

  ______________________________________________________________________

  1.  イントロダクション

  1.1.  最新バージョンの入手場所

  http://www.linuxdoc.org/HOWTO/Bash-Prog-Intro-HOWTO.html

  1.2.  必要事項

  GNU/Linux のコマンドラインに違和感がなく、プログラムについての基本的な
  考え方が身についていると理解しやすいと思います。しかし、この冊子はプロ
  グラミングの技術書ではないので、多くの基本概念について説明を加えて(あ
  るいは少なくともその努力をして)います。

  1.3.  この文書の使い方

  この文書は、次のような場合に役立つことを念頭に置いて書かれています。

  o  プログミングがどういうものか知っていて、これからシェルスクリプトの
     コーディングを始めようとしている場合。

  o  シェルプログラミングについて漠然としか知らないので、参照できる文献
     が欲しい場合。

  o  自分で書き始めるにあたって、実際のスクリプトとそのコメントをいくつ
     か見たい場合。

  o  DOS/Windows 環境から移行しようとしていて(あるいはしてしまって)、
     「バッチ処理」を実現したい場合。

  o  いわゆる完全に「オタク(nerd)」と呼ばれるひとで、片っ端から HOW-TO
     本を読んでいる場合。

  2.  非常にシンプルなスクリプト

  この HOW-TO は、例題に重点を置いて、シェルスクリプトのプログラミングに
  関するヒントを、述べようとしています。

  この章では、いくつかのテクニックを理解するのに役立つような簡単なスクリ
  プトを取り上げます。

  2.1.  伝統の Hello World スクリプト

               #!/bin/bash
               echo Hello World

  このスクリプトは、二行しかありません。一行目は、ファイルを実行するのに
  どのプログラムを使うかをシステムに指示しています。

  二行目は、このプログラムが実行する唯一の命令が書かれていて、それによっ
  て端末に "Hello World" と表示されます。

  もしかすると、./hello.sh: Command not found. と表示されたかもしれませ
  ん。おそらく、最初の行の "#!/bin/bash" が正しくないためでしょ
  う。'whereis bash' と打つか、``「bash を探す(10.3)」''を見るかして、そ
  の行の書き方を確認してください。

  2.2.  非常にシンプルなバックアップスクリプト

               #!/bin/bash
               tar -cZf /var/my-backup.tgz /home/me/

  このスクリプトでは、ターミナルにメッセージを表示するのではなく、ユーザ
  のホームディレクトリの内容を圧縮ファイル(tarball)にまとめます。これは
  実際の使用を意図したものではありません。もっと便利なバックアップスクリ
  プトを、この文書で後ほど紹介します。

  3.  リダイレクトションについて(redirection)

  3.1.  理論と簡単なリファレンス

  bash には、ファイル記述子(file descriptor)として、標準入力 (stdin)、標
  準出力(stdout)、そして標準エラー(stderr) の 3 つがあります。 ( std は
  standard の意味です。)

  基本的に以下のことができます。

  1. stdout を file にリダイレクト

  2. stderr を file にリダイレクト

  3. stdout を stderr にリダイレクト

  4. stderr を stdout にリダイレクト

  5. stderr と stdout を file にリダイレクト

  6. stderr と stdout を stdout にリダイレクト

  7. stderr と stdout を stderr にリダイレクト

  (リダイレクト構文では)数字の 1 は stdout を表し、 2 は stderr を表しま
  す。

  *上記の項目それぞれについての簡単なメモ* less コマンドを使うと、
  stdout (これはバッファに残ります)と stderr (スクリーンには表示されます
  が、そのバッファを見ようとすると消去されてしまいます)の両方を見ること
  ができます。

  3.2.  サンプル: stdout を file へ

  次の場合、プログラムの出力がファイルに書き込まれます。

               $ ls -l > ls-l.txt

  上記では ls-l.txt というファイルが作成されます。そして、'ls -l' という
  コマンドを実行した場合にスクリーンに表示される内容が、そのファイルに保
  存されます。

  3.3.  サンプル: stderr を file へ

  次の場合、プログラムの stderr の出力がファイルに書き込まれます。

               $ grep da * 2> grep-errors.txt

  上記では、grep-errors.txt というファイルが作成されます。そして、その
  ファイルには、'grep da *' の出力のうち、読者が見ようとしているはずの
  stderr の部分が書き込まれています。

  3.4.  サンプル: stdout を stderr へ

  次の場合、プログラムの stderr 出力が、stdout と同一のファイル記述子に
  書き込まれます。
               $ grep da * 1>&2

  上記では、コマンドの stdout の部分が stderr に送られます。別のやり方が
  あることに読者は気付いているかもしれません。

  3.5.  サンプル: stderr から stdout へ

  次の場合、プログラムの stderr 出力が、stdout と同一のファイル記述子に
  書き込まれます。

               $ grep * 2>&1

  上記では、コマンドの stderr の部分が stdout に送られます。したがって、
  もしパイプを使って less に流せば、通常なら stderr に書き込まれて消えて
  しまうはずの出力行が、 stdout に送られたことで保持されているのを確認で
  きます。

  3.6.  サンプル: stderr と stdout から file へ

  次の場合、プログラムの全ての出力がファイルに入れられます。これは、完全
  に黙ってコマンドを実行させたいような cron の実行項目を書く場合に適して
  います。

               $ rm -f $(find / -name core) &> /dev/null

  cron プログラムの実行項目を思い浮かべてほしいのですが、上記は、あらゆ
  るディレクトリから "core" と呼ばれるファイルをすべて削除するものです。
  コマンドの出力を見えなくしてしまう場合は、そのコマンドがどういう処理を
  するのか充分認識しておかなければいけません。

  4.  パイプ (pipe)

  この章では、簡単かつ実用的なパイプの使い方とその有用性について説明しま
  す。

  4.1.  何なのか、どこがいいのか

  簡単にいうと、パイプを使えば、プログラムの出力を他のプログラムの入力と
  して利用できるようになります。

  4.2.  サンプル: sed を使った簡単なパイプ処理

  次の例は簡単なパイプの使い方を示すものです。

               $ ls -l | sed -e "s/[aeio]/u/g"

  上記では、次のことが起こります。先ずコマンド 'ls -l' が実行され、その
  出力が画面に表示される代わりに、sed プログラムに送られ (pipe 処理さ
  れ)、今度は sed がそれを処理して画面に表示します。

  4.3.  サンプル: 'ls -l *.txt' の代替コマンド

  おそらく次は、'ls -l *.txt' とするよりも難しい方法です。これを例題に取
  り上げるのは、ファイルをリストアップするときのジレンマを解消するためで
  はなく、単にパイプの使い方を説明したいからです。

               $ ls -l | grep "\.txt$"

  上記では、'ls -l' プログラムの出力が grep プログラムに送られ、そこで
  "\.txt$" の正規表現に合致する行が画面に出力されます。 (訳注: 上記で円
  マークが表示される場合、それはバックスラッシュの意味です。)

  5.  変数 (variable)

  変数を使えないプログラム言語はありません。ただ、bash にはデータ型(data
  type)がありません。bash の変数は、数字、文字、文字列を格納することがで
  きます。

  変数を宣言する必要はなく、参照すべき変数に値を代入すれば、それだけで作
  成できます。

  5.1.  サンプル: 変数を使った Hello World!

               #!/bin/bash
               STR="Hello World!"
               echo $STR

  2 行目で STR という変数を作って、それに "Hello World" という文字列を代
  入しています。この変数の「値」は変数の最初に "$" を置くことで取り出せ
  ます。もし "$" という記号を使わなかったらプログラムの出力は違うものと
  なり、望んだ結果を得られないということを理解して(あるいは実際にやって
  みて)ください。

  5.2.  サンプル: 非常にシンプルなバックアップスクリプト(改良版)

               #!/bin/bash
               OF=/var/my-backup-$(date +%Y%m%d).tgz
               tar -cZf $OF /home/me/

  上記のスクリプトは、今までとは少し違うことを紹介しています。まず二行目
  にある変数の作成と代入についてはもう慣れたと思います。では、"$(date
  +%Y%m%d)" という表現に注目してください。スクリプトを実行すると、丸カッ
  コのなかのコマンドが実行されて、その出力が取り込まれるようになっていま
  す。

  このスクリプトでは、date コマンドの(+%Y%m%d)という書式スイッチに従っ
  て、出力されるファイル名が毎日変わることに注意してください。違った書式
  を指定することで、これとは異なるファイル名にすることもできます。

  それ以外の参考事例として、

  o  echo ls

  o  echo $(ls)

     といったものがあります。

  5.3.  ローカル変数

  ローカル変数は、local というキーワードを使って作成することができます。

          #!/bin/bash
          HELLO=Hello
          function hello {
                  local HELLO=World
                  echo $HELLO
          }
          echo $HELLO
          hello
          echo $HELLO

  ローカル変数の使い方については、以上の例で充分かと思います。

  6.  条件制御(conditionals)

  条件制御を使えば、ある命令を実行をすべきかどうかの決定ができます。そし
  て、この決定は、式の評価によりなされます。

  6.1.  セオリー

  条件制御には、多くの形式があります。最も基本的な形式は、「if 条件式
  then 実行文」 であり、この実行文は条件式の評価が真であるときだけ実行さ
  れます。" 2 < 1 " というのは偽と評価される条件式であり、" 2 > 1 " とい
  うのは真と評価される条件式です。

  また、条件制御は、「if 条件式 then 実行文1 else 実行文2 」という形式も
  とります。ここでは、条件式が真のとき実行文 1 が実行され、それ以外のと
  きは実行文 2 が実行されます。

  条件制御にはさらに別の形式もあります。「if 条件式1 then 実行文1  else
  if 条件式2  実行文 2  else 実行文3 」 です。この形式では、 "else if 条
  件式2  then 実行文2 " というのが加わっただけですが、これはもし条件式2
  の評価が真ならば実行文2  を実行するものです。その他の部分については、
  読者の想像通りです。(これまでの形式をご覧ください)

  構文に関してですが、 bash で if 制御構造を使うときの基本は以下のような
  ものです。

          if [条件式]
          then
          (if の条件が真だったときの)実行コード
          fi

  6.2.  サンプル: if .. then による基本的な条件制御の例

          #!/bin/bash
          if [ "foo" = "foo" ]; then
             echo expression evaluated as true
          fi

  ブレース [ ] 内の条件式が真であった場合、"then" という文字の後に、実行
  されるコードが書かれています。そしてその後に、条件制御に基づいて実行さ
  れるコードの終了を指示する "fi" が置かれています。

  6.3.  サンプル: "if .. then ... else"  を使った基本的な条件制御の例

               #!/bin/bash
               if [ "foo" = "foo" ]; then
                  echo expression evaluated as true
               else
                  echo expression evaluated as false
               fi

  6.4.  サンプル: 変数を伴った条件制御

               #!/bin/bash
               T1="foo"
               T2="bar"
               if [ "$T1" = "$T2" ]; then
                   echo expression evaluated as true
               else
                   echo expression evaluated as false
               fi

  7.  for, while, until によるループ

  この章では、for, while, そして util によるループについて述べます。
  bash の for は、他の言語での使い方と若干異なります。基本的には、ある文
  字列内の単語をあたまから順に反復処理するものです。

  while は、制御式が真の間はコードを実行していて、偽になったとき (あるい
  は実行コード内に break が明示されている場合)にのみ停止します。

  until ループは、制御式が偽と評価されている間はコードが実行されるという
  点を除くと、while ループとほぼ同じです。while と until が似ていると
  思ったなら、それは正しい考えです。

  7.1.  For のサンプル

               #!/bin/bash
               for i in $( ls ); do
                   echo item: $i
               done

  二行目で、変数 i が宣言されています。これには、$( ls ) によって出力さ
  れる様々な値が(順番に)代入されていきます。三行目は、必要であればもっと
  長くできます。すなわち、四行目の done の前に複数の行が存在してもかまい
  ません。四行目の done は、変数 $i の値を使用していたコードがそこで終了
  したことを示していています。したがって、$i に新しい値を代入することが
  可能です。上記は、はほとんど意味がないスクリプトです。for ループを使用
  するもっと有益な方法は、以前の例題にあったように、ある種のファイルだけ
  を選択的に処理する場合に使うことだと思います。

  7.2.  C 言語に似た for

  Fiesh さんから以下のような形式のループを付け加えたらどうかと言われまし
  た。この for ループは、C 言語や Perl の for ループに類似した使われかた
  をしています。

               #!/bin/bash
               for i in `seq 1 10`;
               do
                       echo $i
               done

  7.3.  while のサンプル

               #!/bin/bash
               COUNTER=0
               while [  $COUNTER -lt 10 ]; do
                   echo The counter is $COUNTER
                   let COUNTER=COUNTER+1
               done

  上記のスクリプトは、(C, Pascal, Perl といった)有名な言語の for の制御
  構造を真似たものです。

  7.4.  until のサンプル

               #!/bin/bash
               COUNTER=20
               until [  $COUNTER -lt 10 ]; do
                   echo COUNTER $COUNTER
                   let COUNTER-=1
               done

  8.  関数(functions)

  ほとんどどんなプログラムに当てはまることですが、関数(function)を使え
  ば、より論理的に一群のコードをグループ化することができます。また、神秘
  的ともいえる再帰法(recursion)を使うことも可能になります。

  関数の宣言は、 "function my_func { my_code }" と書くだけでできます。

  関数の呼び出しは、他のプログラムの呼び出しと同じで、その関数名を書くだ
  けです。

  8.1.  関数のサンプル

               #!/bin/bash
               function quit {
                   exit
               }
               function hello {
                   echo Hello!
               }
               hello
               quit
               echo foo

  二行目から四行目にかけては、"quit" という関数が記述されています。五行
  目から七行目にかけては、"hello" という関数が記述されています。このスク
  リプトが何をしているか完全に把握できないなら、実際に自分で書いて、実行
  してみてください。

  関数は、何らかの特定の様式による宣言を必要としないということに注意して
  ください。

  このスクリプトを実行すると、最初に "hello" 関数が呼び出され、次に
  "quit" 関数が呼び出されます。そしてプログラムは十行目までは実行されな
  いことに気付くでしょう。

  8.2.  パラメーターを取る関数のサンプル

               #!/bin/bash
               function quit {
                   exit
               }
                   function e {
                       echo $1
                   }
               e Hello
               e World
               quit
               echo foo

  上記のプログラムは、前記のプログラムとほぼ同一です。主な違いは、関数
  "e" の存在です。この関数は受け取った第一引数を表示します。引数は、関数
  の内部にあるときでも、スクリプトに直接渡したときと同じように扱われま
  す。

  9.  ユーザインターフェイス

  9.1.  簡単なメニューを作るために select を使う

               #!/bin/bash
               OPTIONS="Hello Quit"
               select opt in $OPTIONS; do
                   if [ "$opt" = "Quit" ]; then
                     echo done
                     exit
                   elif [ "$opt" = "Hello" ]; then
                     echo Hello World
                   else
                     clear
                     echo bad option
                   fi
               done

  もし上記のスクリプトを実行したなら、テキストベースのメニューというプロ
  グラマのひとつの夢が実現しているのが分かると思います。また for の制御
  構造と似ていることにも気付いたかもしれません。$OPTIONS に代入された語
  (word)をひとつずつループさせる代わりに、プロンプトを出力しているという
  違いがあるだけだからです。

  9.2.  コマンドラインを使ってみる

               #!/bin/bash
               if [ -z "$1" ]; then
                   echo usage: $0 directory
                   exit
               fi
               SRCD=$1
               TGTD="/var/backups/"
               OF=home-$(date +%Y%m%d).tgz
               tar -cZf $TGTD$OF $SRCD

  上記のスクリプトが何をするかは、もうお分かりでしょう。最初の条件制御の
  式は、プログラムが引数 ($1)を受け取ったかどうかを調べるものです。そし
  て、引数を受け取らなかったときは簡単な使用方法についてのメッセージを表
  示して終了します。スクリプトの残りの部分は、この時点では明瞭だと思いま
  す。

  10.  その他のスクリプト

  10.1.  read を使ってユーザの入力を読み込む

  ユーザに何らかの入力を促したいと思う場合がよくあるものです。それを実現
  する方法はいくつか存在しますが、以下はそれらのうちのひとつです。

               #!/bin/bash
               echo Please, enter your name
               read NAME
               echo "Hi $NAME!"

  上記の変形として、read を使って複数の値を受け取ることもできます。次の
  例題はそれを明らかにするものです。

               #!/bin/bash
               echo Please, enter your firstname and lastname
               read FN LN
               echo "Hi! $LN, $FN !"

  10.2.  数値の評価

  コマンドライン(あるいはシェル)で、次のように打ってみてください。

               $ echo 1 + 1

  2 が出力されると期待していたなら、がっかりしたことでしょう。 bash に数
  値を計算させたいときは、どうしたらいいのでしょう？解決策は次のようにす
  ることです。

               $ echo $((1 + 1))

  上記では、よりロジカルな出力がなされたことと思います。これは数式を評価
  したということです。また、次のような表現でも同じことができます。

               $ echo $[ 1 + 1 ]

  分数やあるいはもっと複雑な数学的処理が必要になった場合、あるいは数式で
  遊びたいときなどは、数式評価のための bc というコマンドが使えます。コマ
  ンドプロンプト上で "echo $[3/4]" と実行しても、bash は整数でしか答えを
  返せないので、結果は 0 となります。しかし、"echo 3/4 | bc -l" と実行す
  れば、0.75 という正しい答えが返ってきます。

  10.3.  bash を探す

  Mike からのメッセージを掲載します。(謝辞を見てください)

  あなたはいつも #!/bin/bash というのを使っていますが、bash がどこにある
  のか探す方法を例示したほうがいいと思います。"bash をその場所に置いてし
  まえばいいのですが、すべてのマシンがそれをしているわけではありません。
  ルートディレクトリから、'find ./ -name bash' を実行すれば通常は探し出
  せるはずです。

  チェックすべきなのは、次のような場所でしょう。

          ls -l /bin/bash
          ls -l /sbin/bash
          ls -l /usr/lodal/bin/bash
          ls -l /usr/bin/bash
          ls -l /usr/sbin/bash
          ls -l /usr/local/sbin/bash

  (これ以外のディレクトリはすぐに思い浮かびません... システムが違って
  も、これまではこの中から見つかる場合がほとんどでした。) それか
  ら、'which bash' を使ってみるのもいいと思います。

  10.4.  プログラムの戻り値を獲得する方法

  bash では、プログラムの戻り値を $? という特殊な変数に入れておくことが
  できます。以下は、プログラムの戻り値を獲得する方法を書いたものです。た
  だし、 /dada というディレクトリは実在しません。(これも Mike からの提案
  を載せたものです)

               #!/bin/bash
               cd /dada &> /dev/null
               echo rv: $?
               cd $(pwd) &> /dev/null
               echo rv: $?

  10.5.  コマンド出力を獲得する方法

  以下の簡単なスクリプトは、すべてのデータベース上を探して全部のテーブル
  を表示するというものです( MySQL がインストールされていることが前提で
  す)。この中の 'mysql' というコマンド部分を変更して、有効なユーザ名とパ
  スワードが使えるようにしてください。

               #!/bin/bash
               DBS=`mysql -uroot  -e"show databases"`
               for b in $DBS ;
               do
                       mysql -uroot -e"show tables from $b"
               done

  10.6.  複数のソースファイル

  コマンドソースとして複数のファイルを使うことができます。

  作成予定( TO DO )

  11.  参照テーブル

  11.1.  文字列比較演算子

          (1) s1  =  s2    s1 と s2 が同一
          (2) s1 !=  s2    s1 と s2 が同一でない
          (3) s1  <  s2    作成中
          (4) s1  >  s2    作成中
          (5) -n s1        s1 が null でない(一文字以上を含んでいる)
          (6) -z s1        s1 が null である

  11.2.  文字列比較の実例

  ふたつの文字列を比較する

               #!/bin/bash
               S1='string'
               S2='String'
               if [ $S1=$S2 ];
               then
                       echo "S1('$S1') is not equal to S2('$S2')"
               fi
               if [ $S1=$S1 ];
               then
                       echo "S1('$S1') is equal to S1('$S1')"
               fi

  ここで、上記の if [ $1 = $2 ] に関して Andrea Beck が送ってくれたメー
  ルの一文を引用します。

        あまりいい考えとは言えません。もし、$S1 か $S2 のどちらかが空の場合、
        パーサエラーになるからです。x$1=x$2 か "$1"="$2" としたほうがよいで
        しょう。

  11.3.  数値演算子

          +
          -
          *
          /
          % (剰余)

  11.4.  数値関係演算子

          -gt  ( >  )
          -le  ( <= )
          -ge  ( >= )
          -eq  ( == )
          -ne  ( != )

  C プログラマが使っている演算子についても、丸カッコを付けて対応関係を示
  しました。

  11.5.  便利なコマンド

  このセクションは Kees (謝辞を見てください)によってリライトされたもので
  す。

  以下のコマンドのなかには、完全なプログラミング言語を内包しているといえ
  そうなものもあります。それらのコマンドを取り上げて、基本的用法だけを説
  明しよと思います。詳細な解説については、コマンドのマニュアルページをみ
  てください。

  11.5.1.  sed (stream editor)

  sed はノン・インタラクティブなエディタです。カーソルを画面上で動かしな
  がらファイルに変更を加えるかわりに、編集に関する指示と編集すべきファイ
  ル名を書き込んだスクリプトを使用します。また、sed は一種のフィルタであ
  ると考えることもできます。いくつか例を見てみましょう。

               $ sed 's/to_be_replaced/replaced/g' /tmp/dummy

  上記において、sed は、/tmp/dummy というファイルを読み込んで、文字列
  "to_be_replaced" を文字列 "replaced" に置換します。その結果は標準出
  力(通常はコンソール)に出力されますが、上記コマンドラインの末尾に(例え
  ば) '> capture' と付け加えるなら、 "capture" という名前のファイルに
  sed の出力結果を送ることもできます。

          $ sed 12, 18d /tmp/dummy

  上記の例で、sed は 12 から 18 行目までを除く全ての行を表示します。この
  コマンドによって元のファイルに変更が加えられることはありません。

  11.5.2.  awk (データファイルやテキストの検索と整形処理)

  AWK プログラミング言語には多くの実装が存在します。(最も有名なインター
  プリタは、GNU の gawk と「新しい awk」 である mawk です。) AWK の原理
  は単純です。パターンを探して、合致したパターン(pattern)全てに対してな
  んらかの処理(action)を行うということです。

  再度、以下のような行を含むダミーファイルを作りました。

          test123
          test
          tteesstt

               $ awk '/test/ {print}' /tmp/dummy
               test123
               test

  上記において、AWK が探そうとしたパターン(pattern)は "test" であ
  り、/tmp/dummy ファイルの行の中から "test" という文字列を探し出したと
  きに行った処理(action)が画面への表示 "print" です。

               $ awk '/test/ {i=i+1} END {print i}' /tmp/dummy
               3

  数多くのパターンを探そうとしているときは、クオテーション('')で囲まれた
  文字列を(例えば) '-f file.awk' といったファイル名で置き換えます。そう
  すれば、すべてのパターンと処理を 'file.awk' というファイルに書き込ん
  で、まとめて実行できます。

  11.5.3.  grep (検索パターンに合致する行の出力)

  grep コマンドの、あるパターンに合致する行を表示する機能については、こ
  れまでの章でいくつも見てきたと思います。しかし、grep の機能はそれだけ
  ではありません。

               $ grep "look for this" /var/log/messages -c
               12

  上記の例は、"look for this" という文字列が /var/log/messages ファイル
  のなかで 12 回見つかったことを意味しています。

  [ OK, この例題はフェイクなんだ。/var/log/messages にちょっと手を加えと
  いたのさ。 :-)]

  11.5.4.  wc (行、語、バイト数を数えます)

  以下の例題では、出力が期待通りになっていないのが分かると思います。この
  例題で使われたダミーファイルには(前に使った内容とは異なる)次のような文
  字列が含まれていたからでらす。

          bash introduction
          howto test file

               $ wc --words --lines --bytes /tmp/dummy
               2 5 34 /tmp/dummy

  wc ではパラメータ指定の順番は自由ですが、それらの出力時の順番はいつも
  決まっています。上記のように、行数、語数、バイト数、ファイル名 の順番
  になります。

  11.5.5.  sort (テキストファイル内の行の並べ替え)

  今回のダミーファイルの内容は次のようになっています。

          b
          c
          a

               $ sort /tmp/dummy

  次は、そのアウトプットがどう表示されるかです。

               a
               b
               c

  コマンドを使うとすると、これほど簡単にはいかないでしょう。

  11.5.6.  bc (数値計算用のプログラミング言語)

  bc はコマンドラインで操作するよくできた計算プログラムです。リダイレク
  トやパイプからは入力できませんが、ファイルからの入力が可能で、ユーザイ
  ンターフェイスもあります。以下では、そのコマンドの中からいくつかを実際
  にデモンストレーションしてみます。なお、bc 起動時に -q パラメータを使
  用しているのは、起動時にウェルカムメッセージを出力させないためです。

               $ bc -q
               1 == 5
               0
               5 != 5
               0
               2 ^ 8
               256
               sqrt(9)
               3
               while (i != 9) { i = i + 1; print i }
               12345689
               quit

  11.5.7.  tput (端末の初期化や terminfo データベースの検索)

  tput でなにができるか、簡単に紹介します。

               $ tput cup 10 4

  上記の例では、プロンプトが (y10,x4) の位置にあらわれます。

               $ tput reset

  上記では、画面をもとに戻して、(y1,x1) の位置にプロンプトを表示しま
  す。(y0,x0) がちょうど左上の隅にあたる位置です。

               $ tput cols
               80

  上記では、X 軸方向に文字がいくつ並ぶのかを表示しています。

  (少なくとも)上記のようなプログラムについては、使い慣れておくことを強く
  お薦めします。コマンドライン上の操作で驚くほどの処理をしてくれる小さな
  プログラムは無数にあります。

  [例題のいくつかは、マニュアルページや FAQ から取りました。]

  12.  いろいろなスクリプト

  12.1.  ディレクトリ上の全ファイルにコマンドを適用する方法

  (作成中)

  12.2.  サンプル: 非常にシンプルなバックアップスクリプト(改良版)

               #!/bin/bash
               SRCD="/home/"
               TGTD="/var/backups/"
               OF=home-$(date +%Y%m%d).tgz
               tar -cZf $TGTD$OF $SRCD

  12.3.  ファイル名変更スクリプト

               #!/bin/sh
               # renna: いくつかのルールに従って、複数のファイルをリネームする
               # スクリプト: Felix Hudson Jan 2000

               # 最初にこのプログラムが取るいくつかの「モード」についてチェックする
               # 第一引数($1)の条件が一致するなら、プログラムの該当部分を実行して
               # 終了する

               # prefix の条件をチェックする
               if [ $1 = p ] ; then

               # モード変数($1)と prefix ($2)を取り除く
               prefix=$2 ; shift ; shift

               # ファイルが指定されているか簡単にチェックする
               # 指定されていないときは、存在しないファイルをリネームすることは
               # できないので、なにもしない
               if [$1 = ]; then
                    echo "no files given"
                    exit 0
               fi

               # プログラムの引数となるファイルを順にループ処理する
               # ファイルをひとつずつリネームする
               for file in $*
                   do
                   mv ${file} $prefix$file
               done

               # ここでプログラムを終了する
                   exit 0
               fi

          # suffix をリネームするかチェックする
          # ここでの残りの部分は上記とおなじ処理なので、そちらを見てほしい
          if [ $1 = s ]; then
              suffix=$2 ; shift ; shift

          if [$1 = ]; then
              echo "no files given"
              exit 0
          fi

          for file in $*
              do
               mv ${file} $file$suffix
              done
              exit 0
          fi

               # 名前の置き換えかどうかをチェックする
               if [ $1 = r ]; then
                   shift

               # ユーザが処理の内容を指定しなかったとしてもファイルがダメージを
               # 受けないように、次のコードを含めた
               if [ $# -lt 3 ] ; then
                   echo "usage: renna r [expression] [replacement] files... "
                   exit 0
               fi

               # 余計な情報を削除する
               OLD=$1 ; NEW=$2 ; shift ; shift

          # この for ループはプログラムに与えられたファイルを順に処理する
          # sed というプログラムを使って、ファイルをひとつずつリネームする
          # sed は標準入力を読み込んで、特定の表現を与えられた文字列に置換する
          # ここでは、標準入力からファイル名を指定して、必要な文字を置換させる
          for file in $*
              do
               new=`echo ${file} | sed s/${OLD}/${NEW}/g`
               mv ${file} $new
              done
              exit 0
          fi

               # ここまで来たとすると、プログラムに引数がなかったということなので、
               # 使い方を表示する
               echo "usage;"
               echo " renna p [prefix] files.."
               echo " renna s [suffix] files.."
               echo " renna r [expression] [replacement] files.."
               exit 0

               # 終了

  12.4.  ファイル名変更スクリプト(簡易版)

               #!/bin/bash
               # renames.sh
               # basic file renamer

               criteria=$1
               re_match=$2
               replace=$3

               for i in $( ls *$criteria* );
               do
                   src=$i
                   tgt=$(echo $i | sed -e "s/$re_match/$replace/")
                   mv $src $tgt
               done

  13.  うまくいかない時(デバッグ)

  13.1.  bash の呼び出し方

  効果的なのは、第一行目にちょっと手を加えることです。

               #!/bin/bash -x

  こうすると、出力に際に面白い情報が表示されます。

  14.  この文書について

  提案や訂正、またこの文書に掲載すべき面白い事柄などなんでもお気軽に連絡
  してください。できるだけ早く反映させます。

  14.1.  (無)保証について

  This documents comes with no warranty of any kind. and all that (ママ)

  この文書には、いかなる保証も伴いません。

  14.2.  翻訳について

  イタリア語: by Willy Ghelfi (wizzy at tiscalinet.it) こちら

  フランス語: by Laurent Martelli ( URL は不明)

  韓国語: Minseok Park http://kldp.org

  韓国語: Chun Hye Jin ( URL は不明)

  スペイン語: 訳者不明 http://www.insflug.org

  もっと多くの翻訳があると思うのですが、情報がありません。御存知のかた
  は、わたしにメールをください。この章を更新します。

  14.3.  謝辞

  o  この文書を翻訳してくれたひとたち(前章)

  o  Nathan Hurst は詳細に校正してくれました。

  o  Jon Abbott は数式の評価についてコメントを送ってくれました。

  o  Felix Hudson は renna スクリプトを書いてくれました。

  o  Kees van den Broek (校正に協力し、便利なコマンドの章をリライトして
     くれました)

  o  Mike (pink) は bash の位置を特定したりファイルをテストしたりするこ
     とについていくつか提案してくれました。

  o  Fiesh はループの章についていい提案をしてくれました。

  o  Lion はコマンドエラーについて述べるよう提案してくれまし
     た。(./hello.sh: Command not found.)

  o  Andrea Beck は校正とコメントについて協力してくれました。

  14.4.  改訂履歴

  o  翻訳が新規に追加され、いくつか訂正を加えた。

  o  Kees のリライトによる便利なコマンドの章を付け加えた。

  o  訂正を提案を大幅に取り入れた。

  o  文字列比較について実例を増やした。

  o  v0.8 バージョン情報を外した。日付で充分だと思う。

  o  v0.7 訂正箇所多数。TO-DO の章を書き直し。

  o  v0.6 すこし訂正

  o  v0.5 リダイレクトの章を追加

  o  v0.4 前任のボスの意向でそれまでのページで公開できなくなったが、この
     文書にとっては最適の場所が見つかった。 <http://www.linuxdoc.org/>

  o  それ以前のことは覚えていない。rcs も cvs も使っていなかった。

  14.5.  参考ホームページ

  ( BeOS での)bash に関する紹介
  <http://org.laol.net/lamug/beforever/bashtut.htm>

  Bourne Shell のプログラミング <http://207.213.123.70/book/>

  14.6.  日本語訳について

  翻訳 千旦 裕司  <ysenda@pop01.odn.ne.jp>
  校正 井上 秀悟  <shyugoro@pop12.odn.ne.jp>
       武井 伸光  <takei@webmasters.gr.jp>
       伊藤 祐一  <kade@kadesoft.com>

