IT pass HikiWiki - [Exp2012]シェル Diff

  • Added parts are displayed like this.
  • Deleted parts are displayed like this.

((<"スケジュール表・各回資料 (06/01)"|[Exp2012]スケジュール表・各回資料#06-2F01>))

{{toc}}

= 実習の前準備

本日の実習を始める前に
((<実習の前準備|[Exp2012]実習の前準備>))
を行って下さい.

= 本日の御題

* シェルの役割
  * シェルとは何か?
* シェルの使い方
* vi エディタの使い方
  * ファイルオープン/ファイルクローズ
  * 簡単な編集方法
* シェルスクリプト
  * スクリプトの作り方
* 課題

※ 今回の実習は作業が多いため, まずは「◎」 がついた項目のみ作業してください. 「○」 がついた項目は 「◎」 を終えてから作業してください.
その他の部分に関しては参考資料ということで, 必要になったら適宜読んでください. ※

なお, 以下のように $ から始まる行をみなさんに実際に入力してもらいます.
それ以外の行は出力例です.

$ pwd
/home/ykawai

環境によっては異なる動作をすることもあるので,
出力例と異なった出力が現れても, マシンが壊れたものと早合点しないように
(たまに, この資料が間違っていることもあります).
なぜ例と異なる出力が出たのか考えてみると良い勉強になります.

= シェル (Shell) とは

シェルとは, ユーザーから入力されたコマンドを解釈し, システムの根幹部であるカーネルとの橋渡しを行うプログラムです. 他の OS で機能的に似た役割を持つものとして,  Windowsでは Explorer, Macintosh(MAC)では finder があります. しかし, イメージとしては Windows95/98 の DOS プロンプトや,  Windows2000/XP/Vista/7 のコマンドプロンプトの方が近いでしょう.

通常, シェルは login シェルとして, 各ユーザがログインする度に起動され, ログアウトの際に終了します. ログインすると, 端末の上に, 例えば "samson$" と表示されますが, これがシェルが発している「プロンプト」(ユーザへコマンドの入力を促す記号)です. 尚, xterm 等のターミナルを新たに立ち上げると別のシェルが起動されます.

UNIX の内部構造をみると, 核となる部分はカーネル(Kernel)と呼ばれ, マルチタスクやファイルシステム, 仮想記憶, 入出力など,  OS にとって重要な機能を司っています. ユーザーはカーネルを直接操るのではなく, あらかじめ用意されたインターフェイス(窓口)を通して, カーネルに対してコマンドの実行を要求します. このインターフェイスの部分がシェルであり, つまりシェルはユーザとカーネルの仲立ちをしているプログラムであると言えるでしょう.

例えると直接は言葉の通じない相手 (kernel と呼ばれるプログラム) とあなたがコミュニケーションをする際に必要となるこまごまとした準備や通訳などをこなしてくれる秘書 or 通訳?? さんの様な役割をはたしてくれるのが "シェル" (shell) と呼ばれるプログラムです. 普段意識しないと存在に気づかないのですが, 実は非常に有能なプログラムです. 彼 (or 彼女?) の上手な使い方を覚えることは UNIX の能力を最大限活用するのに不可欠です.

シェルは xterm 等のターミナル上で実行しますので, ターミナルを立ち上げないとシェルというカーネルに対する窓口が使えません. 最近の Window Manager は賢くなって X 上に色々なアイコンを表示してくれ, それをクリックすると firefox 等が起動するようになっています. しかし正しい作法はターミナルを立ち上げ, そこのシェルを通じて様々なプログラムを起動することです.

# [確認] なぜ, カーネルを直接操作できないのでしょうか?
# なぜ, わざわざシェルなんてものを挟むのでしょうか?


= シェルの役割

シェルには大きく分けて3つの役割があります.

* ユーザーインターフェース(コマンド・インタプリタとしてのシェル)
  * プロンプトの表示
  * コマンドの読み込み
  * コマンドの前処理(解釈)
  * コマンドの実行
* 環境設定の道具
* プログラミング言語(スクリプトを解釈する論理的な制御機能としてのシェル)

= 代表的なシェルの紹介

主要なシェルには以下のようなものがあります.

* sh(Bourne shell, B shell):
現在利用できるもっとも古いシェル.  AT&T のベル研究所で開発され,  開発者の1人であるSteven Bourne 氏にちなんで名付けられた.  色々なシェルの中で共通項的な位置にあり,  ほとんど全ての UNIX で利用できる標準的なシェルであるため,  シェルスクリプトの作成には B シェルがよく用いられる.
* csh(c shell):
カリフォルニア大学バークレイ校の William Joy 氏が中心になって開発したシェルで,  C 言語に似た構文を持つことから, この名前が付けられている.  B シェルに比べ, ヒストリー機能やジョブ制御,  エイリアスなどの機能が付加されており, 対話形式で使用する場合に便利である.
* bash(Bourne Again shell):
MIT(マサチューセッツ工科大学)の Brian Fox 氏が作成したシェルで,  現在, GNU ソフトウェアの一部として配布されている.  bash は, 元来 B シェル において貧弱であった,  ユーザーインターフェイスとしての機能を強化するため,  ヒストリー機能, エイリアスなどが追加されている.
* その他:
csh の拡張版である tcsh(TC shell)や, zsh, ksh などがあります.  


= 利用するシェルの確認と変更
== 現在, 自分がどのシェルを使っているか調べる方法

$ set | grep SHELL

$ finger username

== 自分のログインシェルの変更方法

(注意) 以下のこのコマンドは実習では行わなくて構いません.

$ chsh

次にログインするときに, 変更したシェルが起動されます.  (管理者の設定により無理な場合があります).

= ◎ bash の機能

ここでは, bash のコマンドラインにおける入出力やジョブ制御など, 基礎的な事項についてまとめています.

== リダイレクション

cat, echo, date などのコマンドを入力すると, 結果が表示されます. これらの結果をファイルに書き込みたい場合はリダイレクションを使います.

$ echo "hello world" > hello.txt   <-- 「>」が echo "hello world"
                                         の結果を hello.txt に書き込む.
$ cat hello.txt                    <-- hello.txt の中身を表示させる
hello world                        --> 表示

$ cat hello.txt > world.txt        <-- 次にhello.txtの中身をworld.txtにリダイレクト
$ cat world.txt                    <-- world.txt の中身を表示させる
hello world                        --> 表示

$ date >> world.txt                <-- 「>>」を使うと上書きされずに追加される.
$ cat world.txt                    <-- world.txt の中身を表示させる
hello world                        --> 表示
Sat Oct 26 00:41:30 JST 2002

== メタキャラクタ(ワイルドカード)

コマンド入力の際に, 複数のファイル名を「ある規則にしたがってまとめて表す」という試みのために用いられる文字のことを,  "メタキャラクタ"(ワイルドカード)と言います. メタキャラクタを用いると, タイプする文字数を減らすことができるので, 効率的に入力が行えます.


代表的なメタキャラクタ
  # RT
  delimiter = %

  メタキャラクタ% 意味
  *% 任意の文字列を表す.
  ?% 任意の1文字を表す. ?? は任意の2文字になる.
  [ ]% [ ] 内に含まれる文字にマッチする. 例えば [a-c]* は abc のいずれかで始まる任意の文字列を表す.
  { }% { }内に含まれる文字列にマッチする. 例えば test.{pl,gif,f} は test.pl test.gif test.f と入力したことになる.

この機能は便利で, * (アスタリスク) は良く使います.

$ mkdir work/
$ cp *.txt work/      <-- カレントディレクトリ内で末尾が .txt という
                           ファイルを work 以下に移動させる.
$ rm *.txt            <-- カレントディレクトリ内で末尾が .txt という
                           ファイルを消去する.

但しいくら便利だからといって以下のコマンドを実行してはいけません. 絶対に禁止!!!

$ rm *

また,

$ rm *.txt

のつもりで

$ rm * .txt

とやる致命的なミスもよくあるので注意しましょう
(上の 2 つは何が違うのか考えてみましょう).

== パイプ

上記のリダイレクションでは表示される結果をファイルに書き出しました. これに対し, パイプ「|」を使用すると結果をコマンドに送ることができます.

$ ls -la /usr/bin                        <-- /usr/bin 以下のファイルを表示
(略)                                     --> 大量の情報が表示される

$ ls -la /usr/bin | less                 <-- パイプ「|」で結果をコマンド「less」に送る
(略)                                     --> 結果を less で見ることができる.

$ ls -la /usr/bin | grep "gnome" | less    <-- パイプを連続で使うことで複数のコマンドを連結して使うこともできる.
                                          (「grep」コマンドで "gnome" という文字列を含む行のみを抽出し, 結果を less で見る)
(略)



== ジョブ制御

ジョブ(Job)とは, ユーザがコンピュータに行なわせる仕事の単位です.

bash には, 1つのシェルで複数のジョブを切替えながら, 並行して作業を行う機能があります. これをジョブ制御と呼びます.

* フォアグランドジョブ:
通常シェルでコマンドを実行すると, その作業はジョブとして登録され, そのコマンドが終了するまで次のコマンドを実行することが出来ません. このような状態にあるジョブを"フォアグランドジョブ"と言います.
* バックグラントジョブ:
これに対して, コマンドの末尾に & を付けて実行すると, シェルはコマンドの終了を待たずに, すぐ次のコマンドを受け付ける状態になります. このように, 即座に次のジョブを実行できるよう, 背後で実行されている状態のジョブを"バックグランドジョブ"と言います. バックグランドジョブとして動作しているジョブの一覧を表示させるには,  jobs コマンドを用います.  

上記2種のジョブを制御するために,  bash には fg, bg, jobs コマンド, そして & が用意されています.

はじめフォアグランドジョブとして起動されたコマンドを, バックグランドジョブに変更するには, (フォアグランドジョブが実行されているために)プロンプトが表示されていない状態の端末で,  Ctrl-z(コントロール・キーを押しながら z キーを押す)として, ジョブを中断させます.

$ xterm &                         <-- ( xterm を新たに起動すると起動したターミナルに制御が移りますが,
                                       マウス等を使って初めのターミナルに戻って作業を続けて下さい. )
$ xclock
^Z                                <-- Ctrl-z を押します
[2]+  Stopped          xclock     --> ジョブ番号[2]の xclock が停止しました

次に jobs と打ち込み, 現在このシェルから実行中のジョブ一覧を表示させます.

$ jobs
[1]-  Running          xterm &    --> ジョブ番号[1]の xterm が実行中です
[2]+  Stopped          xclock     --> ジョブ番号[2]の xclock が停止中です

xclock より前に xterm が実行されていたので, 上のような表示になります.  [ ]の中の数字はジョブの番号を表します. +は "current job", - は"previous job"と呼ばれ, ジョブの切替え対象となる順番を表しています.

bg コマンドを用いると, フォアグランドジョブをバックグランドジョブに切り替えることが出来ます. (bg の後に % ジョブ番号と入力)

$ bg %2
$ jobs
[1]-  Running          xterm &     --> ジョブ番号[1]の xterm が実行中です
[2]+  Running          xclock &    --> ジョブ番号[2]の xclock が実行中です

逆に, バックグランドジョブをフォアグランドジョブに切り替えるには,  fg コマンドを用います. (ジョブ番号の指定の仕方は, bg コマンドと同様)

$ fg %1
xterm

フォアグラウンドジョブは, Ctrl-c(コントロール・キーを押しながら c キーを押す)として, 終了させることもできます. フォアグラウンドジョブが正常終了できなくなった場合等に有効です.

^C                 <-- Ctrl-c を押します
$                  --> プロンプトが表示され入力可能となります. xterm は終了します.

バックグラウンドジョブを終了させるには, kill コマンドを用います.

$ kill %2                          <--ジョブ番号[2]の xclock に終了シグナルを送る.
[2]+  終了しました       xclock

== ファイル, コマンド名の補完機能

bash には, 途中まで打ち込まれた内容を元に,  ファイルやコマンドを補完する機能が備わっています.  具体的には, 目的の文字列を何文字か入力し, Tab キーを押します.  複数候補が存在する場合は, Tab キーを2回押すことで,  その一覧を表示させることが出来ます.  この機能は他にも, シェル変数, ユーザー名, ホスト名なども補完してくれます.

$ ls /[Tab][Tab]        <-- [Tab] は Tab キーを押します
bin          etc          lib          root         var        --> 「/」以下のファイル
boot         floppy       lost+found   sbin         vmlinuz         の候補が表示されます
cdrom        home         mnt          opt          tmp
vmlinuz.old  dev          initrd       proc         usr          
$ ls /h[Tab]
$ ls /home/             --> 「/home/」が補完されます

Tab 以外の補完機能
  # RT
  キー操作, 意味
  Esc ?, 補完候補のリストを一覧する
  Esc /, ファイル名として補完を行なう
  Esc !, コマンドとして補完を行なう
  Esc Tab, 以前に実行したコマンドの補完を試みる

== ヒストリ機能

bash には便利なヒストリ機能が存在します. この機能によって以前に入力したコマンドを簡単に呼び出すことができます.

$ cat .bashrc        <-- 何らかのコマンドを入力してみる.
$                    --> シェルのプロンプト
$ cat .bashrc        <-- 「↑」, または Ctrl-p
                          (コントロール・キーを押しながら p キーを押す)
                          と以前に入力したコマンドを呼び出すことができる.

history コマンドを入力すると今までに入力したコマンドが表示されます.
これらの情報は ~/.bash_history に格納されています.

== シェルの組み込みコマンド

シェルで実行できるコマンドの種類には, 「外部コマンド」,「組み込みコマンド」, 「エイリアスで定義されたコマンド」等があります. 「外部コマンド」は /bin/, /usr/bin/ 以下のディレクトリに個別に格納されており (例: ls, xterm) , 「組み込みコマンド」はシェルのプログラムに直接組み込まれています.「組み込みコマンド」には以下のようなものがあります.

echo, set, unset, alias, history, cd, ...

help コマンドを利用すると, これら組み込みコマンドの, 簡単な説明を得られます.

* (help で説明可能な)組み込みコマンドの一覧を表示:

$ help

* 組み込みコマンドの説明を表示:

$ help [組み込みコマンド名]

コマンドに関するマニュアルは, man というコマンドを用いることで得られます.

* 外部コマンドに関するマニュアル

$ man [外部コマンド名]

* 組み込みコマンドに関するマニュアル (bash の場合)

$ man bash


= ○ 環境のカスタマイズ (bash の場合)

# BASH(1) の パラメータ > シェル変数 を参照
== シェル変数

bashは, シェル自身の動作を定義する変数を持っています. この, シェルが内部で保持している変数を, "シェル変数"と言います. シェルスクリプトや, コマンドの入力の際に, 値を一時的に格納して後で再利用できるようにするための変数でもあります. 後述する環境変数と違い, シェル以外のプログラムからは参照できません.

基本的に, 変数名をつける際は, 好きなようにつけて構わないのですが, すでに定義されている変数とは重ならないように指定した方が無難です.

* 現在設定されているシェル変数を見るには, set と打ち込みます.
* シェル変数の設定と変更は, "="を使います. (シェル変数名=シェル変数の値)
* シェル変数の値を調べるには, echo $変数名 と打ち込みます.
* シェル変数の削除は, unset コマンドを使います. (unset シェル変数名)

シェル変数に値を代入して, そのシェル変数を表示させて見ましょう.

$ var='Hello!'     <-- シェル変数 var に Hello! を代入
$ echo $var        <-- シェル変数 var を表示
Hello!             --> シェル変数 var 内の値が表示されます

$ unset var        <-- シェル変数 var を削除
$ echo $var
                    --> なにも表示されません

もう一つの例として, プロンプトの表示を変えてみましょう. プロンプトの表示は, シェル変数"PS1"を用いて設定することが出来ます.

$ PS1="\u% "                    <-- プロンプト表示を"ユーザ名%"にする
                                     (詳細は以下の表を参照)
user%                           --> userは自分のユーザ名

user% PS1="\d$ "                <-- プロンプト表示を"日付%"にする
Fri Nov 26$

Fri Nov 26$ PS1="\s-\v\$ "      <-- プロンプト表示を"シェルの名前-バージョン"にする
bash-2.01$

bash-2.01$ PS1="\u@\h:\w\$ "    <-- プロンプト表示を"ユーザ名@ホスト名:作業ディレクトリ"にする
user@joho:~$

# BASH(1) のプロンプトを参照
プロンプト表示のコマンド
  # RT
  コマンド, 意味
  \d, 日付
  \H, ホスト名
  \h, 最初の"."までのホスト名
  \n, 改行
  \s, シェルの名前
  \u, 現在のユーザ名
  \v, bash のバージョン
  \w, 現在の作業ディレクトリ
  \!, 現在のコマンドのヒストリ番号


== 環境変数

シェル変数はシェルの中だけで使われる変数ですが, こちらは, アプリケーションやコマンドなどの動作を統一的に制御するために, ユーザーが設定する変数です.

有名な環境変数
  # RT
  環境変数名, 意味
  USER, ユーザ名
  HOST, ホスト名
#  LC_ALL,
#  LANG,
#  LANGUAGE, 言語環境. 日本語ならば ja_JP.eucJP, 英語ならば C. LC_ALL による言語設定はほぼ全てのアプリケーションに関して有効である.  LANG, LANGUAGE はアプリケーションに よって有効になる場合とならない場合がある.
  PATH, コマンドサーチパス
  HOME, ホームディレクトリ

* 現在設定されている環境変数を見るには, printenv と打ち込みます.
* 環境変数の設定と変更は, export コマンドを使います.
* 環境変数の値を調べるには, printenv 変数名と打ち込みます.  

シェル変数・環境変数には, あらかじめ使い方が決められたものがあり, 変更には注意が必要です.

例として, 以下の4つのコマンドを順番に入力してみてください.

$ export LC_ALL=C
$ man man
$ export LC_ALL=ja_JP.eucJP
$ man man
$ export LC_ALL=ja_JP.utf8
$ man man

これを実際に試してみると, 一度目の man man と二度目の man man で出力される結果が違うのが, 確認できると思います. 環境変数とはこのように, あらかじめ設定していた文字列によってプログラムの動作を規定する為のものです. (プログラム側で対応していない場合は効果ありません)

次に以下のコマンドを実行して下さい.

$ echo $PATH                                <-- 環境変数 PATH を表示させます
/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:
$ date                                      --> date コマンドで
Fri Nov  1 14:18:18 JST 2002                    現在の時刻が表示されます.

$ export PATH=""                            <-- 環境変数 PATH を空にします.
$ date
bash: date: command not found               --> date コマンドは無いと言われました.
$ /bin/date                                 <-- date コマンドの絶対パスを指定しました.
Fri Nov  1 14:18:18 JST 2002                --> 現在の時刻が表示されます.

$ export PATH="/usr/local/bin:/usr/bin:/bin:/usr/bin/X11:"    <-- 環境変数 PATH の設定を元に戻します.
$ date
Fri Nov  1 14:18:18 JST 2002                --> date コマンドで
                                                 現在の時刻が表示されます.

すると最初は存在していたはずの date コマンドが存在しないと言われるでしょう. コマンドもファイルですから本来は絶対パスで書かねばならないのですが, PATH 環境変数にコマンドの置かれているディレクトリを指定しておくとコマンド名そのもので実行できます.

== エイリアス(別名)機能

あるコマンドに対して, 別名をつけたいときに用います.

alias 別名 = コマンド名

alias 別名 = 'オプション付きのコマンド名'

rm -i を rm と変更

$ echo "hello world" > hello.txt      <-- hello.txt ファイルを作成
$ rm hello.txt                        <-- hello.txt ファイルを削除

$ echo "hello world" > hello.txt      <-- hello.txt ファイルを作成
$ alias rm='rm -i'                    <-- rm -i を rm として登録
$ rm hello.txt                        <-- hello.txt ファイルを削除
rm: remove `test.txt'?                --> -i オプションをつけなくても削除の確認の問い合わせをしてくれる
$ unalias rm                          <-- alias を無効化する

== 起動ファイル, 環境定義ファイル

環境変数やシェル変数, aliasを設定 or 変更しても, そのシェルを終了したりログアウトした場合その設定や変更は消えてしまいます. 一時的な変更ではなく個人で恒常的に環境変数やシェル変数を変更する場合, ホームディレクトリ以下に存在する .bashrc, .bash_profile を編集します. 例えば自分の作成したプログラムやスクリプトの置場にも PATH を通す場合, .bashrc や .bash_profile を編集する必要があるでしょう. この 2 つのファイルの役割は以下のようになっています.

.bashrc と .bash_profile の役割
  # RT
  ファイル名, 役割
  .bash_profile, ログインシェルの設定.
  .bashrc, ログインシェル以外のシェルの設定

ログインシェルとはユーザがログインした時直後に現れるシェルのことです (情報実験機のログインシェルは bash です.). ターミナル(xterm 等)を起動すると一緒にシェルも起動されますが, そのシェルは .bashrc を読み込んでいます. 2 つ設定ファイルがあって紛らわしいかもしれませんが, 混同しないようにしましょう.

.bash_profile,.bashrc 共に「シェルスクリプト」になっています (シェルスクリプトに関しては後述します. ). それらのファイルの中身はコマンドが羅列してあると考えて下さい. ですから ls --color を ls にエイリアスし, LC_ALL 環境変数を日本語にしたかったらファイル内に以下の 2 行だけ書いておけば良いです.

# Create an alias for the ls command
alias ls='ls --color'
# Set the language locale to EUC-JP
export LC_ALL=ja_JP.eucJP

= その他のシェル

ここでは bash について説明しましたが, 時間があれば他のシェルも試しに使ってみましょう.
以下では ash について解説します.

$ ash                   <-- これが最も初期の「sh」である.
>                       --> ashのプロンプト (bash とは違うモノが表示されるはず)
> ^[[A^[[A^[[D^[[D      <-- ヒストリ機能は使えず, カーソルキー(矢印キー)
                             を押してもこんな文字が表示されるだけ.
> exit                  <-- 元のシェルに戻る.

他にも情報実験機では csh, tcsh を使うことができます.

= 参考資料

このページは
((<"北海道大学 理学院 情報実験 (INEX)"|URL:http://www.ep.sci.hokudai.ac.jp/~inex>))

((<"最低限 UNIX / Linux [III] シェル (2007 年度資料)"|URL:http://www.ep.sci.hokudai.ac.jp/~inex/y2007/1026/jitsugi/shell.html>))
を基に作成しました.

((<"スケジュール表・各回資料 (06/01)"|[Exp2012]スケジュール表・各回資料#06-2F01>))