BASH Programming - Introduction HOW-TO by Mike G Mon Jul 27 11:47:00 ART 2000 日本語訳 千旦裕司 July 2000 この文書は、初中級のシェルスクリプトのプログラムを始める人の手引書として書か れています。(タイトルからも分かるように)これは高度な内容を解説した文書ではあり ません。わたし自身、シェルプログラムのエキスパートではないですし、ましてや達人 でもありません。これを書こうと思い立ったのは、そこから自分が多くを学べるだろう と思ったからであり、もしかしたら他人の役に立つかもしれないと考えたからです。 どんなフィードバックも歓迎します。特に、パッチ形式でいただけると嬉しく 思います :) イントロダクション 最新バージョンの入手場所

必要事項

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

この文書は、次のような場合に役立つことを念頭に置いて書かれています。 プログミングがどういうものか知っていて、これからシェルスクリプトの コーディングを始めようとしている場合。 シェルプログラミングについて漠然としか知らないので、参照できる文献が 欲しい場合。 自分で書き始めるにあたって、実際のスクリプトとそのコメントをいくつか 見たい場合。 DOS/Windows 環境から移行しようとしていて(あるいはしてしまって)、 「バッチ処理」を実現したい場合。 いわゆる完全に「オタク(nerd)」と呼ばれるひとで、片っ端から HOW-TO 本を 読んでいる場合。 非常にシンプルなスクリプト

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

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

#!/bin/bash echo Hello World

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

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

もしかすると、./hello.sh: Command not found. と表示されたかもしれ ません。おそらく、最初の行の "#!/bin/bash" が正しくないためで しょう。'whereis bash' と打つか、を見るかして、その行の書き方を確認してください。 非常にシンプルなバックアップスクリプト

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

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

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

基本的に以下のことができます。 stdoutfile にリダイレクト stderrfile にリダイレクト stdoutstderr にリダイレクト stderrstdout にリダイレクト stderrstdoutfile にリダイレクト stderrstdoutstdout にリダイレクト stderrstdoutstderr にリダイレクト (リダイレクト構文では)数字の 1stdout を表し、 2stderr を表します。

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

次の場合、プログラムの出力がファイルに書き込まれます。 $ ls -l > ls-l.txt

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

次の場合、プログラムの stderr の出力がファイルに書き込まれます。 $ grep da * 2> grep-errors.txt

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

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

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

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

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

次の場合、プログラムの全ての出力がファイルに入れられます。これは、完全に 黙ってコマンドを実行させたいような cron の実行項目を書く場合に適して います。 $ rm -f $(find / -name core) &> /dev/null

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

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

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

次の例は簡単なパイプの使い方を示すものです。 $ ls -l | sed -e "s/[aeio]/u/g"

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

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

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

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

変数を宣言する必要はなく、参照すべき変数に値を代入すれば、それだけで 作成できます。 サンプル: 変数を使った Hello World!

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

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

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

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

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

それ以外の参考事例として、 echo ls echo $(ls) といったものがあります。 ローカル変数

ローカル変数は、local というキーワードを使って作成することができ ます。 #!/bin/bash HELLO=Hello function hello { local HELLO=World echo $HELLO } echo $HELLO hello echo $HELLO

ローカル変数の使い方については、以上の例で充分かと思います。 条件制御(conditionals)

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

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

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

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

構文に関してですが、 bashif 制御構造を使うときの基本は以下のようなものです。 if [条件式] then (if の条件が真だったときの)実行コード fi サンプル: if .. then による基本的な条件制御の例

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

ブレース [ ] 内の条件式が真であった場合、&dquot;then&dquot; という 文字の後に、実行されるコードが書かれています。そしてその後に、条件制御に基づ いて実行されるコードの終了を指示する &dquot;fi&dquot; が置かれて います。 サンプル: "if .. then ... else" を使った基本的な条件制御の例

#!/bin/bash if [ "foo" = "foo" ]; then echo expression evaluated as true else echo expression evaluated as false fi サンプル: 変数を伴った条件制御

#!/bin/bash T1="foo" T2="bar" if [ "$T1" = "$T2" ]; then echo expression evaluated as true else echo expression evaluated as false fi for, while, until によるループ

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

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

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

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

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

Fiesh さんから以下のような形式のループを付け加えたらどうかと言われました。 この for ループは、C 言語や Perl の for ループに類似した 使われかたをしています。 #!/bin/bash for i in `seq 1 10`; do echo $i done while のサンプル

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

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

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

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

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

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

関数のサンプル

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

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

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

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

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

上記のプログラムは、前記のプログラムとほぼ同一です。主な違いは、 関数 "e" の存在です。この関数は受け取った第一引数を表示します。 引数は、関数の内部にあるときでも、スクリプトに直接渡したときと同じように扱わ れます。 ユーザインターフェイス 簡単なメニューを作るために 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)をひとつずつループさせる代わりに、プロンプトを出力しているという違いが あるだけだからです。 コマンドラインを使ってみる

#!/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)を受け取ったかどうかを調べるものです。そして、 引数を受け取らなかったときは簡単な使用方法についてのメッセージを表示して終 了します。スクリプトの残りの部分は、この時点では明瞭だと思います。 その他のスクリプト 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 !" 数値の評価

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

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

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

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

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' を使ってみるのもいいと思います。 プログラムの戻り値を獲得する方法

bash では、プログラムの戻り値を $? という特殊な変数に入れて おくことができます。 以下は、プログラムの戻り値を獲得する方法を書いたものです。ただし、 /dada というディレクトリは実在しません。(これも Mike からの提案を 載せたものです) #!/bin/bash cd /dada &> /dev/null echo rv: $? cd $(pwd) &> /dev/null echo rv: $? コマンド出力を獲得する方法

以下の簡単なスクリプトは、すべてのデータベース上を探して全部のテーブルを 表示するというものです( MySQL がインストールされていることが前提で す)。 この中の 'mysql' というコマンド部分を変更して、有効なユーザ名とパス ワードが使えるようにしてください。 #!/bin/bash DBS=`mysql -uroot -e"show databases"` for b in $DBS ; do mysql -uroot -e"show tables from $b" done 複数のソースファイル

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

作成予定( TO DO ) 参照テーブル 文字列比較演算子

(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 である 文字列比較の実例

ふたつの文字列を比較する #!/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" としたほうがよいで しょう。 数値演算子

+ - * / % (剰余) 数値関係演算子

-gt ( > ) -le ( <= ) -ge ( >= ) -eq ( == ) -ne ( != ) C プログラマが使っている演算子についても、丸カッコを付けて対応関係を示しまし た。 便利なコマンド

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

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

上記の例で、sed12 から 18 行目までを除く全ての 行を表示します。このコマンドによって元のファイルに変更が加えられることはあり ません。 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' というファイルに書き 込んで、まとめて実行できます。 grep (検索パターンに合致する行の出力)

grep コマンドの、あるパターンに合致する行を表示する機能については、 これまでの章でいくつも見てきたと思います。しかし、grep の機能はそれ だけではありません。 $ grep "look for this" /var/log/messages -c 12

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

[ OK, この例題はフェイクなんだ。/var/log/messages にちょっと手を加え といたのさ。 :-)] wc (行、語、バイト数を数えます)

以下の例題では、出力が期待通りになっていないのが分かると思います。この例題で 使われたダミーファイルには(前に使った内容とは異なる)次のような文字列が含まれ ていたからでらす。 bash introduction howto test file $ wc --words --lines --bytes /tmp/dummy 2 5 34 /tmp/dummy

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

今回のダミーファイルの内容は次のようになっています。 b c a $ sort /tmp/dummy

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

コマンドを使うとすると、これほど簡単にはいかないでしょう。 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 tput (端末の初期化や terminfo データベースの検索)

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

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

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

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

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

[例題のいくつかは、マニュアルページや FAQ から取りました。] いろいろなスクリプト ディレクトリ上の全ファイルにコマンドを適用する方法

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

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

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

#!/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 # 終了 ファイル名変更スクリプト(簡易版)

#!/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 うまくいかない時(デバッグ) bash の呼び出し方

効果的なのは、第一行目にちょっと手を加えることです。 #!/bin/bash -x

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

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

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

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

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

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

韓国語: Minseok Park

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

スペイン語: 訳者不明

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

この文書を翻訳してくれたひとたち(前章) Nathan Hurst は詳細に校正してくれました。 Jon Abbott は数式の評価についてコメントを送ってくれました。 Felix Hudson は renna スクリプトを書いてくれました。 Kees van den Broek (校正に協力し、便利なコマンドの章をリライトしてくれ ました) Mike (pink) は bash の位置を特定したりファイルをテストしたりすることに ついていくつか提案してくれました。 Fiesh はループの章についていい提案をしてくれました。 Lion はコマンドエラーについて述べるよう提案してくれました。(./hello.sh: Command not found.) Andrea Beck は校正とコメントについて協力してくれました。 改訂履歴

翻訳が新規に追加され、いくつか訂正を加えた。 Kees のリライトによる便利なコマンドの章を付け加えた。 訂正を提案を大幅に取り入れた。 文字列比較について実例を増やした。 v0.8 バージョン情報を外した。日付で充分だと思う。 v0.7 訂正箇所多数。TO-DO の章を書き直し。 v0.6 すこし訂正 v0.5 リダイレクトの章を追加 v0.4 前任のボスの意向でそれまでのページで公開できなくなったが、この文書 にとっては最適の場所が見つかった。 それ以前のことは覚えていない。rcs も cvs も使っていなかった。 参考ホームページ

( BeOS での)bash に関する紹介

Bourne Shell のプログラミング 日本語訳について

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