情報処理 I - 第4回


1.シェルスクリプト


1.1 コマンドとして csh を起動してみる

ターミナルのウィンドウを開いたときに実行されるシェル (csh) 自体も、ひとつのコマンドです。

csh
csh を起動してみる。
% csh[Enter]
%              ←何も起こらなかったように見える
実は csh の中で csh が起動している。だから、それまでと変わらずコマンドが使える。
% date[Enter]
1998年 5月17日(日曜日) 03時38分38秒 JST
csh を終了してみる。シェルを終了させるには exit コマンドを使う。
% exit[Enter]
%              ←やっぱり何も起こらなかったように見える
もう一度 exit コマンドを入力してみる。 こんどはターミナルのウィンドウが閉じる。
% exit[Enter]

2回目の exit コマンドを入力すると、ターミナルのウィンドウが閉じて(消えて)しまいます。これはターミナル (rxvt) が起動したシェル (csh) の終了をずっと待っており、シェルが終了すると自分も終了するように作られているからです。

なお、シェルで exit コマンドの代わりに Ctrl-D をタイプすること(すなわち入力データの終了)でも、シェルを終了することができます(これを無効にする設定もあります)。利用者が入力するコマンドは、シェルにとっては入力データというわけです。

1.2 シェルにファイルからコマンドを与えてみる

シェルへのコマンド入力がシェルにとっては入力データに他ならないなら、シェルに入力するコマンドを一旦ファイルに記録しておいて、それをシェルの入力に与えることもできるはずです。

シェルへのデータ入力
date, cal, pwd コマンドを連続して実行してみる。
% date[Enter]
1998年 5月17日(日曜日) 03時38分38秒 JST
% cal[Enter]
   1998 年 5 月
日 月 火 水 木 金 土 
                 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
% pwd[Enter]
/home/s3/s075000
cat コマンドを使って、a というファイルの中に date、cal、pwd を書き込んでみる。
% cat > a[Enter]
date[Enter]
cal[Enter]
pwd[Enter]
Ctrl-D
ファイル a の内容を見てみる。
% cat a[Enter]
date
cal
pwd
ファイル a の内容を csh の入力に流し込んでみる。
% csh < a[Enter]

つまりシェルのコマンドを、キーボードからではなくファイルから与えることによって、一連のコマンドを連続して実行することが可能になります。これは同じ作業を繰り返す場合などに便利です。

実はシェルも cat と同様に、引数に与えたファイル名のファイルからデータを読み取ることができます。

シェルの引数
csh コマンドの引数にファイル名を指定する。
% csh a[Enter]

1.3 自分専用のコマンドを作る

ファイルの先頭でコマンドを解釈するシェルを明示し、そのファイルに実行権を与えれば、それを新しいコマンドとして使えるようになります。このようなファイルをシェルスクリプトと呼びます。

シェルスクリプトの作成
cat コマンドを使って c というファイルを作る。中身は1行だけ。
% cat > c[Enter]
#!/bin/csh -f[Enter]
Ctrl-D
cat コマンドを使って、c の後ろに a の内容を追加する。
% cat a >> c[Enter]
ファイル a の内容を見てみる。c の内容に a の内容が追加されていなければやり直し。
% cat c[Enter]
#!/bin/csh -f
date
cal
pwd

最初の行の "#!" によって、そのシェルスクリプトを解釈するシェルを指定します。上のシェルスクリプトでは /bin というディレクトリにある csh コマンドによって解釈しますから、それを絶対パスで指定します。csh に与えているオプション -f は、csh 起動時の設定ファイルの読み込みを省略します。詳しくは man tcsh を読んでください。

ファイルを実行可能にする
ファイル c のアクセス権を確認する。
% ls -l c[Enter]
-rw-r--r--    1 s075000  students       27 May  7 09:30 c
chmod コマンドを使って c に実行権を追加する。
% chmod +x c[Enter]
もう一度ファイル c のアクセス権を確認する。
% ls -l c[Enter]
-rwxr-xr-x    1 s075000  students       27 May  7 09:30 c

ls コマンドに -l オプションをつけると、ファイルの詳細な情報を表示します。先頭の1文字はファイルのタイプを示し、これが "-" なら通常のファイル、"d" ならディレクトリであることを示します。続く9文字はファイルのアクセス権 (permission) を示します。これは3文字ずつに区切られ、それぞれファイルの所有者、グループに属するユーザ、それら以外のユーザが、そのファイルにアクセスする際の権利を表しています。

上の例でファイル c は、その所有者による読み出し、書き込み、および実行が可能ですが、所有者以外は読み出しと実行しかできません。グループに属するユーザも書き込み可能にするには chmod g+w c とします。また、その他のユーザ (others) が読み出し・実行ともできないようにするには chmod o-rx c とします。詳しくは man chmod を読んでください。

なお、ファイルによっては x のところが t や s になっていることがあります。それぞれ特別な意味を持ちますが、ここでは割愛します。

シェルスクリプトの実行
ファイル c を実行する。
% ./c[Enter]

"./c" はカレントディレクトリ (.) にある c を実行するということです。ちゃんと実行できたでしょうか?


2.シェル変数


2.1 変数とは

変数はプログラム中でデータを一時的に格納しておく入れ物です。プログラミング言語において変数は、最も基本的で重要な要素です。シェルにおいて変数は、その動作を制御するために利用されますが、シェル自身がプログラミング言語としての側面を持っているため、変数を使うことでさらに柔軟な処理を行うことができます。

2.2 csh のシェル変数

csh の場合、シェル変数への代入には set コマンドを使います。また、変数の値を参照する(取り出す)には、変数名に $ を付けます。

シェル変数 (csh)
変数 name に ichiro を代入してみる。変数 name は自動的に作られる。
% set name=ichiro[Enter]
echo コマンドを使って、name の内容を見てみる。echo コマンドは引数をそのまま標準出力に出力する。
% echo $name[Enter]
ichiro
echo には複数の引数が指定できる。
% echo My name is $name[Enter]
My name is ichiro
代入する文字がスペースを含むときは "~" や '~' でくくる。
% set my="My name is"[Enter]
% echo $my $name[Enter]
My name is ichiro
set コマンドは複数の変数への代入ができる。expr は引数を数式とみなして計算するコマンド。
% set v1=10 v2=20[Enter]
% echo $v1 $v2[Enter]
10 20
% expr $v1 + $v2[Enter]
30
値が数値なら set の代わりに @ を使うと、変数への代入のときに計算ができる。
% @ v3=$v1 + $v2[Enter]
% echo $v3[Enter]
30
set コマンド単独で実行するとシェル変数を全部表示する。
% set[Enter]
シェル変数を消去するには unset コマンドを使う。
% unset v1 v2 v3[Enter]
% echo $v1[Enter]
v1: 変数を定義していません.

2.3 特別なシェル変数

シェル変数の中には、シェルの動作の制御などに使われるものがあります。シェルにおいても、入力の終了を示す Ctrl-D をタイプするとシェルが終了してしまいます。これを防ぐためには ignoreeof というシェル変数を設定します。

ignoreeof (EOF <End Of File: ファイルの終わり> の無視)
シェルで Ctrl-D をタイプしてみる。多分、シェルが終了して、ターミナルのウィンドウが閉じる。
% Ctrl-D
もう一度ターミナルを開いて、シェル変数 ignoreeof をセットする。
% set ignoreeof[Enter]
また Ctrl-D をタイプしてみる。今度はシェルが終了しない。
% Ctrl-D
csh終了は"exit"を使用して下さい
exit コマンドで csh が終了する。
% exit[Enter]

csh を終了したので、ターミナルのウィンドウが閉じてしまったと思います。もう一度ターミナルを開いてください。

コマンドの標準出力をファイルにリダイレクトしたとき、リダイレクト先のファイルが既に存在すれば、もとから合った内容は消えて、リダイレクトしたデータと置き換わってしまいます。リダイレクトによって間違ってファイルの内容を消してしまわないようにするには、noclobber というシェル変数を設定します。

noclobber(リダイレクトによる上書き禁止)
echo コマンドを使って、a に「かばやねん」を入れる。a には「かばやねん」が入っている。
% echo かばやねん > a[Enter]
~ 8> cat a[Enter]
かばやねん
echo コマンドを使って、a に「たこやねん」を入れる。それまでに a に入っていた「かばやねん」は消えて、かわりに「たこやねん」が入っている。
% echo たこやねん > a[Enter]
% cat a[Enter]
たこやねん
シェル変数 noclobber を作る。
% set noclobber[Enter]
echo コマンドを使って、e に「いかやねん」を入れてみる。こんどはエラーになる。
% echo いかやねん > a[Enter]
a と言うファイルは既に存在します.  ←エラーになる
でも ">!" を使うと無理やり入れることができる。
% echo いかやねん >! a[Enter]  ←エラーにならない
% cat a[Enter]
いかやねん

今度はプロンプト(入力促進符号、シェルがコマンド待ちであることを示す記号、ここでは % のこと)を変えてみましょう。プロンプトは prompt というシェル変数を使って設定します。

prompt(プロンプトの設定)
変数 prompt に値を代入してみる。引用符号 (") は日本語の入力モードを抜けてから入力すること。
% set prompt="なんやねん "[Enter]
なんやねん 
プロンプトにカレントディレクトリを含めることができる。%c がカレントディレクトリ名に置き換わる。"~" はホームディレクトリを示す。これは tcsh の拡張機能である。
なんやねん set prompt="%~ >"[Enter]
~ >cd /usr/bin[Enter]
/usr/bin >cd[Enter]
~>
プロンプトにイベント番号(後述)を含める。"!" は csh では特別な意味を持つ文字なので、前に "\" を付けてその意味を打ち消す。""(バックスラッシュ)は、画面やキーボード上では""(円記号)で表示されることがあります。
~>set prompt="%~ \!> "[Enter]
~ 6> echo $prompt[Enter]
%~ !>  ←"\"自体は残らない
~ 7>  ←コマンドを実行するたびに数が増える

これらの設定を解除するには、unset コマンドを使ってシェル変数を消去します。


3.コマンドのサーチパス


通常使うコマンドは、/usr/bin など、どこか他のディレクトリに収められています。コマンドを実行するには、それが収められている場所も含めて指定する必要があります。しかし、それではコマンドが長くなりすぎるので、サーチパスを設定して、どこにあるコマンドを使うのかを指定しています。

サーチパス
date コマンドを実行してみる。
~ 7> date[Enter]
2002年  5月  8日 水曜日 11:30:45 JST
which コマンドを使えば、どこにあるコマンドを実行したのか調べることができる。
~ 8> which date[Enter]
/bin/date  ←date コマンドは /bin ディレクトリにある
コマンドを絶対パス名で指定することもできる。
~ 9> /bin/date[Enter]
2002年  5月  8日 水曜日 11:31:22 JST
サーチパスに含まれないところにあるコマンドは実行できない。
~ 10> fortune[Enter]
fortune: コマンドが見つかりません.
しかし、これもコマンドの絶対パス名を指定すれば実行できる。fortune は「今日の一言」みたいなコマンド。
~ 11> /usr/games/fortune[Enter]
(何かメッセージが出る)
シェル変数 path を表示する。コマンドはこれらのディレクトリの中から、この順番に探される(表示される内容はこの限りではない)。/usr/games は含まれていない。
~ 12> echo $path[Enter]
/usr/local/bin /bin /usr/bin /usr/X11R6/bin
path に /usr/games を追加する。
~ 13> set path=( $path /usr/games )[Enter]
path を確認する。/usr/games が含まれいているはず。
~ 14> echo $path[Enter]
/usr/local/bin /bin /usr/bin /usr/X11R6/bin /usr/games
もう一度 fortune を実行してみる。今度は実行できるはず。
~ 15> fortune[Enter]
(何かメッセージが出る)

なお、set コマンドや次にあげる history コマンド、alias コマンドなどは、csh の組み込みコマンドと呼ばれ、csh 自身が処理しています。したがって ls のように独立したコマンドはありません。


4.history 機能


プログラミングなどをしていると、何度も同じコマンドを入力することがよくありますが、コマンドが長かったりすると結構面倒です。csh には以前に入力したコマンドを記録しておく機能がありますので、それを使って以前のコマンドを再利用できます。

history
シェル変数 history に、記録するコマンドの数を設定する。
~ 16> set history=100[Enter]
history コマンドでこれまでに入力したコマンドの一覧が表示される。
~ 17> history[Enter]
     1  11:00 set prompt="なんやねん "
   (中略)
    17  11:20 history
"!!" で直前に実行したコマンドを再度実行できる。
~ 18> !![Enter]
history          ←再実行するコマンドが表示される
イベント番号 1 のコマンドを再度実行する。
~ 19> !1[Enter]
set prompt="なんやねん "
なんやねん 
最近に実行した "ec" で始まるコマンドを再度実行する。
なんやねん !ec[Enter]
echo $prompt
なんやねん 
シェル変数 savehist を設定しておけば、csh 終了後もコマンドの履歴を覚えていてくれる。
なんやねん set savehist=100[Enter]
!!
直前に実行したコマンドを再度実行する。
!番号
番号に指定したイベント番号のコマンドを再度実行する
!コマンド
コマンドで始まる最近のコマンドを再度実行する

なお、tcsh では矢印キーを使って以前のコマンドを呼び出したり、編集したりすることができます。他にもたくさんの機能がありますから、man コマンドを使って調べてください。


5.コマンドの別名


alias (エイリアス)コマンドを使って、コマンドに別名をつけることができます。alias の設定を解除するには、unalias コマンドを使います。

alias
"ls -l" に ll という別名を付ける。ll で ls -l が実行される。
% alias ll 'ls -l'[Enter]
% ll[Enter]
rm コマンドは有無を言わさずにファイルを消してしまう。
% touch xxx[Enter]  ←適当なファイル xxx を作る
% rm xxx[Enter]
%                    ←何も言わずにファイルを消してしまう
それではちょっと怖いので、rm に -i オプションを付ける。一応確認してくれる。消すなら y、消さないなら n を入力する。
% touch xxx[Enter]  ←適当なファイル xxx を作る
% rm -i xxx[Enter]
rm: remove `xxx'? y ←一応聞いてくれる
rm で必ず "rm -i" が実行されるようにする。
% alias rm 'rm -i'[Enter]
rm コマンドを使ってファイルを消してみる。今度は -i オプションを付けなくても確認してくれる。
% touch xxx[Enter]  ←適当なファイル xxx を作る
% rm xxx[Enter]
rm: remove `xxx'? y ←こんどは -i を付けなくても聞いてくれる
別名の途中にコマンドの引数を置きたいときは、!* を使う。この場合も "\" を使って "!" がもつ特別な意味を打ち消す。
% alias lm 'ls -l \!* | less'[Enter]
% lm .*[Enter]
alias の設定を解除するには、unalias コマンドを使う。
% unalias lm[Enter]
% lm .*[Enter]
lm: コマンドが見つかりません.

6.環境変数


環境変数はシェル変数と似ていますが、シェル変数がシェル内でのみ有効な変数なのに対して、環境変数はそのシェルから起動したプログラムに引き継がれます。環境変数自体はオペレーティングシステムの機能です。

環境変数の設定には setenv コマンド、解除には unsetenv コマンド、一覧には printenv コマンドを使います。set コマンドとは異なり、setenv コマンドでは "=" は使いません。

環境変数 (csh)
HENSU という変数を表示するだけのスクリプト b を作る
% cat > b[Enter]
#!/bin/csh -f[Enter]
echo $HENSU[Enter]
Ctrl-D
b を実行可能にする。
% chmod +x b[Enter]
b を実行してみる。多分エラーになる。
% ./b[Enter]
HENSU: 変数を定義していません.
set コマンドでシェル変数に値を与えてもエラーになる。
% set HENSU=10[Enter]
% ./b[Enter]
HENSU: 変数を定義していません.
setenv コマンドで環境変数に値を与える。今度は多分うまくいく。
% setenv HENSU 10[Enter]
% ./b[Enter]
10

シェル変数 path と環境変数 PATH や シェル変数 term と環境変数 TERM など、一部のシェル変数は環境変数と同期しています。

シェル変数 path と環境変数 PATH
シェル変数 path を見てみる。
% echo $path[Enter]
/usr/local/bin /bin /usr/bin /usr/X11R6/bin /usr/games
環境変数 PATH を見てみる。
% echo $PATH[Enter]
/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin:/usr/games
シェル変数 path をひとつ切り詰めてみる。$path[1-4] は path の1番目から4番目までの要素を切り出す(最初 path には5つの要素が入っているとする)。
% set path=( $path[1-4] )[Enter]
シェル変数 path をもう一度見てみる。ひとつ切り詰められている。
% echo $path[Enter]
/usr/local/bin /bin /usr/bin /usr/X11R6/bin
環境変数 PATH をもう一度見てみる。これも切り詰められている。
% echo $PATH[Enter]
/usr/local/bin:/bin:/usr/bin:/usr/X11R6/bin

7.シェルの初期設定


ホームディレクトリの .cshrc というファイルに書いたコマンドは、シェルの起動時にあらかじめ実行されます。これを使ってシェルの初期設定ができます。

.cshrc の作成
ホームディレクトリに戻る(今どこにいるのかわからないので)。
% cd[Enter]
たとえば set history=100 を .cshrc に入れてみる。
% cat > .cshrc[Enter]
set history=100[Enter]
Ctrl-D

なお、この読み込みは csh の起動時にしか行われないので、.cshrc の設定は新たに開いたターミナルで有効になります。現在使っているシェルでその設定を有効にするには source コマンドを使います。

.cshrc の読み込み
source コマンドを使って、.cshrc を現在使っている csh に読み込む。
% source .cshrc[Enter]

課題


(1)ファイル c を、所有者だけが読み出し・書き込み・実行できるようにアクセス権を設定してください。そのコマンドを答えてください。

(2)man tcsh を見て、プロンプトに現在時刻を含める設定を考えてください。そのコマンドを答えてください。

(3)cp、mv、rm コマンドについて、それらが常に -i オプション付きで実行されるように alias を設定してください。また、それらを .cshrc に入れてください。