ソフトウェア工学 A

NAGASAKA Yasunori

2009/09/29

http://edu.isc.chubu.ac.jp/naga/index.html で公開中


 Table of Contents


1   はじめに (第 1 週)
 1.1   凡例
 1.2   目標
 1.3   進め方
 1.4   建設的な横着とは
 1.5   練習問題

2   基本的な使い方 (第 1 週)
 2.1   Linux の起動と終了
 2.2   GNOME, X Window System の使い方
 2.3   端末(ターミナル)エミュレータの使い方
 2.4   Web ブラウザ firefox の使い方
 2.5   出席確認用ファイルの作成方法

3   エディタ (第 1, 2 週)
 3.1   gedit
 3.2   vi (p.161)
  3.2.1   vi の代表的なコマンド
  3.2.2   vi の操作の実際
 3.3   emacs (p.152)
  3.3.1   emacs の代表的なコマンド
  3.3.2   emacs の操作の実際
 3.4   日本語入力 (p.170)
 3.5   練習問題

4   UNIX, Linux の特徴 (第 2, 3 週)
 4.1   UNIX, Windows の特徴と相違点 (p.22)
 4.2   Login, Logout (p.36)
 4.3   一般ユーザと特権(管理者)ユーザ (p.38)
 4.4   パスワード (p.36,59)
 4.5   シェル, Shell (p.64,115)
 4.6   コマンド (p.45,66)
 4.7   man, オンラインマニュアル (p.40,82)
 4.8   練習問題

5   データを記録、参照する仕組 (第 4, 5 週)
 5.1   ファイルとディレクトリ (p.72,87)
 5.2   パス : ファイルの位置 (p.56,87)
 5.3   ファイルの属性、アクセス制限 (p.92)
  5.3.1   アクセス権、アクセス制限の詳細
 5.4   練習問題

6   コマンド (第 6, 7 週)
 6.1   凡例
 6.2   UNIX の代表的なコマンド
  6.2.1   ディレクトリ操作 (p.103)
  6.2.2   ファイル操作 (p.91,96)
  6.2.3   テキストファイル操作 (p.96,103)
  6.2.4   ユーティリティ (p.177)
  6.2.5   プロセス制御 (p.192)
 6.3   練習問題

7   シェルによる操作環境 (p.115) (第 8, 9 週)
 7.1   コマンドラインの編集、文字列補完 (p.144)
 7.2   ファイル名の置換、字句解析 (p.143)
 7.3   エイリアス (p.145)
 7.4   ヒストリ (p.141)
 7.5   シェル変数 (p.139)
 7.6   環境変数 (p.136)
 7.7   設定ファイル .cshrc, .login (p.147)
 7.8   標準入出力、リダイレクト、パイプ (p.118,122)
 7.9   ジョブコントロール (p.125)
 7.10   練習問題

8   パターン処理言語 awk (第 10, 11 週)
 8.1   awk の概要、実行方法
 8.2   awk のプログラム : 変数
 8.3   awk のプログラム : パターンの記述
 8.4   正規表現
 8.5   awk のプログラム : アクションの記述
 8.6   サンプルプログラム
 8.7   練習問題

9   シェルスクリプト、作業の自動化 (第 12, 13 週)
 9.1   シェルスクリプトとは
 9.2   変数、パラメータ
 9.3   コマンド置換
 9.4   引用、クォート
 9.5   制御構造
  9.5.1   if
  9.5.2   for
  9.5.3   while
  9.5.4   break
  9.5.5   continue
 9.6   ファイル名の操作
 9.7   シェルスクリプトの例
  9.7.1   大文字の拡張子 JPG を小文字の jpg に変更する
  9.7.2   一定の形式のファイル名で通し番号を付けてファイルを作成する
  9.7.3   デジタルカメラの画像ファイルの名前を内容がわかるファイル名に変更する
  9.7.4   ls の結果を日時をファイル名にしたファイルに記録する
  9.7.5   複数のファイルで特定の単語を含む行数の一覧表を作成する
  9.7.6   学生の出席日数を数える
 9.8   練習問題

10   OS が備える主要な機能
 10.1   カーネル
 10.2   プロセス、スケジューリング
 10.3   メモリ管理、仮想記憶
 10.4   ファイルシステム
 10.5   システムコール
 10.6   ユーザインタフェース
 10.7   入出力、割り込み
 10.8   通信、ネットワーク
 10.9   練習問題

11   基本的な使い方 (旧システム用)
 11.1   X Window System の使い方
 11.2   kterm の使い方
 11.3   Web ブラウザ firefox, mozilla の使い方
 11.4   出席確認用ファイルの作成方法



1   はじめに (第 1 週)


1.1   凡例

  この後の文中ではコンピュータで実際に実行するコマンド、命令文の記述が数多く現れる。 そのようなコマンドについては、
% ls -la
のように記述される。この場合、端末エミュレータのコマンドプロンプト ("a01%" のようにコンピュータ名と % の組み合わせで表される) に続けて ls -la を入力して Enter (Ret も可) キーを入力することで実行される。 文中左端の % はコマンド入力であることを表しているので、 自分で入力する必要はない。

  各章のタイトルには参考書の関連した記述のページを付記してあるので、 併せて読んで参考にするとよい。
参考書 : 「UNIX本格マスター 基礎編」, 後藤大地, 小澤正紀, (技術評論社) 



1.2   目標

  1. UNIX, Linux の基本を理解して使えるようになる。

  2. 大量のデータに対して、 様々な処理を組み合わせないとできない複雑な処理を行ないたい場合に、 コンピュータでいかに効率良く実行できるようにするか、 その方法、考え方を身に付ける。

  3. OS の役割、処理の基本、関連する概念を理解する。



1.3   進め方



1.4   建設的な横着とは

  コンピュータを「建設的な横着」をするための機械ととらえる。

  一定の手順、単純な作業を多数回繰り返す場合に、人が手でやるのではなくて コンピュータに必要な指示を与えてかわりにやらせること、作業を自動化すること。 同じ時間をかけるなら、人間の能力は単純作業の繰り返しに使うのではなく、 その作業をコンピュータにやらせるにはどうしたらよいか「考える」ところに使うべき。

  建設的な横着ができるようになるための、方法、考え方を身に付けることを目指す。



1.5   練習問題

  1. あなたの知っている OS を挙げてみなさい。

  2. 普段パーソナルコンピュータ、Windows をどんなことに使っているか考えなさい。

  3. OS の機能にはどんなものがあるか考えなさい。 (情報処理工学で既出)

  4. デジタルカメラで撮影した画像ファイルが 10 個ある。 内容がわかるファイル名に変更したい場合、自分ならどう実行するか考えなさい。

  5. デジタルカメラで撮影した画像ファイルが 100 個ある。 内容がわかるファイル名に変更したい場合、自分ならどう実行するか考えなさい。

  6. デジタルカメラで撮影した画像ファイルが 1000 個ある。 内容がわかるファイル名に変更したい場合、自分ならどう実行するか考えなさい。

デジタルカメラの画像ファイルの名前の例
DCN00001.jpg → ryokou0001.jpg
DCN00002.jpg → ryokou0002.jpg
DCN00003.jpg → ryokou0003.jpg
DCN00004.jpg → ryokou0004.jpg
DCN00005.jpg → ryokou0005.jpg
  ・
  ・
  ・
DCN00999.jpg → ryokou0999.jpg
DCN01000.jpg → ryokou1000.jpg




2   基本的な使い方 (第 1 週)


2.1   Linux の起動と終了



2.2   GNOME, X Window System の使い方

  X Window System は UNIX, Linux で標準的に使用されるビットマップディスプレイ、マウス、 Window 等を使用する GUI の実装である。 GNOME は X Window System 上で動作する統合デスクトップ環境である。



GNOME の画面



2.3   端末(ターミナル)エミュレータの使い方



端末エミュレータの画面



2.4   Web ブラウザ firefox の使い方



firefox の画面



2.5   出席確認用ファイルの作成方法

  2009 年度から教務課が運用するカードリーダーの出席登録状況で確認するので、 下記の出席確認ファイルを作成する必要はなくなった。





3   エディタ (第 1, 2 週)

  GNOME の環境で使用する代表的なエディタとして gedit がある。 GUI を考慮して開発されており、多くの編集コマンドがメニュー形式で利用できる。 Windows 環境のアプリケーションに似たコマンド体系になっているので、 Windows に慣れている人は理解し易い。

  UNIX で使用するその他の代表的なエディタとして vi, emacs がある。 どちらも非常に高機能なエディタで、 キーボードからのコマンドの入力ですべての編集機能が利用でき、 一旦コマンドを覚えるとほとんどの操作をキーボードから行なえるので、 早く効率良く文書作成ができる。その反面、GUI, メニューなどはないので、 慣れるまでは使いこなすのが難しいと感じるかもしれない。

  すべてのエディタの使い方に精通する必要はないので、どれか一つ、 自分が使い易いと感じたものの使い方を覚えればよい。 また、すべてのコマンドを覚える必要はないが、 効率良く作業を進めるにはカーソルキーの移動と文字の削除だけでは不足するので、 指定した範囲をまとめて削除、コピーする方法程度は覚える必要がある。


3.1   gedit



gedit の画面の例

  gedit は多くの編集コマンドがメニューおよびボタンの形式で利用できるので、 Windows のメモ帳やワードパッド、Word などのプログラムを使用した経験があれば、 マニュアル等を読まなくても容易に使え、初心者でも使い易い。 メニューの項目は Windows のアプリケーションのメモ帳に類似しており、日常的に Windows を使用する人は馴染み易いと思われる。

  文書作成時にはファイルメニュー、編集メニュー内の機能を利用することが多い。 以下にそれぞれのメニューに含まれる機能の一覧を示す。



gedit のメニュー(1)



gedit のメニュー(2)



3.2   vi (p.161)

  vi は、コマンドモードと挿入(インサート)モードという二つのモードを 必要に応じて切替えながら編集を行なう、 モードを強く意識したエディタである。 コマンドモードでは、編集したい位置に移動したり、 いろいろな編集機能を指定するコマンド(命令)が実行できる。 挿入モードでは、文字を入力する。 特徴として、同じ文字がその時のモードにより異なる意味を持つ。 例として、文字'h'はコマンドモードではカーソルの左への移動として解釈され、 挿入モードでは入力文字としてカーソル位置に挿入される。

  Windows, Unix どちらの環境でも、 vi のように操作状態を 2 種類のモードで明確に区別しているエディタは数少ないので、 はじめて使用する場合は多少戸惑うかもしれない。



vi におけるモードの遷移

  挿入モードとコマンドモード間の切替えは、 コマンドモードから挿入モードへは、以下の挿入コマンドのどれかによって、 また挿入モードからコマンドモードへは ESC キーを入力することで切り替える。

  ヤンクとは,カットバッファに記憶することを表す。
ペーストとは,カットバッファの内容を挿入することを表す。

  挿入モードでは、基本的に文字の入力しかできないが、 オリジナルの vi から機能拡張された新しい vi の実装(vim, この講義でも使用している)では、 文字入力に加えて、上下左右のカーソルキーによるカーソルの移動、 BS および DEL キーによる文字の削除が可能になっている。

  起動の仕方は、
% vi filename
のように、起動時に編集対象のファイルを同時に指定するか、または、
% vi
として起動しておいて、 以下の ex コマンドのファイル挿入コマンドで必要なファイルを指定して読み込む。

  操作を間違えた時、表示がおかしくなった時は、ESC キーを入力すると直る場合がある。


3.2.1   vi の代表的なコマンド

  以下に示すコマンドはすべてコマンドモードで実行する

○ exコマンド

:w : 現在のファイルに書き込む
:w filename : 指定したファイルに書き込む
:q : エディタの終了
:q! : エディタの強制終了(記録していない編集内容は破棄される)
:r : 現在のファイルを挿入
:r filename : 指定したファイルを挿入
:help : ヘルプを表示

(※ :wq : ファイルに書き込んでから終了、のように組み合わせての指定が可能)

○ 中止

ESC : コマンドの実行を中止する

○ 挿入コマンド

i : カーソルの前に挿入
I : 行の先頭文字の前に挿入
a : カーソルの後に挿入
A : 行末に挿入
o : 次行に挿入
O : 前行に挿入

○ 移動コマンド

h : カーソルを一文字左に移動
j : カーソルを一行下に移動
k : カーソルを一行上に移動
l : カーソルを一文字右に移動
^ : 行頭文字に移動
0 : 行頭に移動
$ : 行末に移動
[数字]G : [数字]行に移動
G : 最終行に移動
Ctrl+F : 次画面に移動
Ctrl+B : 前画面に移動
/[文字列] : [文字列]を検索 (n で次候補, N で前候補)

○ 編集コマンド

x : 文字の削除 (DEL, Delete)
X : 文字の削除 (BS, BackSpace)
d[移動コマンド] : 移動範囲を削除
dd : 行の削除
y[移動コマンド] : 移動範囲をヤンク
yy : 行のヤンク
p : カーソルの後(次行)にペースト
P : カーソルの前(前行)にペースト

  上記に示したコマンドは多くのコマンドの中の一部に過ぎないが、 より詳しく vi の機能を知りたい場合は、チュートリアルプログラムを利用するとよい。 起動の仕方は、
% vimtutor
とする。その後は画面の指示にしたがって実際に操作しながら練習ができる。


3.2.2   vi の操作の実際

  以下では vi を使用して文書を入力する時の典型的な操作の例を示す。
通常は編集対象のファイル(仮に sample.txt)を指定して起動する。
% vi sample.txt
カーソルの移動などが必要ならここで行なっておく。 現在はコマンドモードになっているので挿入モードに変更する。 次の行頭の(コマンド)はコマンドモードからの入力を表す。
(コマンド) i
挿入モードになると画面下端に次のように表示されるのでわかる。
-- 挿入 --
この状態で文字入力が可能となる。必要な文字を入力していき、編集コマンドを実行する時は、 適宜コマンドモードに変更して編集する。 一通り入力が終ったらファイルを記録して終了する。
(コマンド) :wq
ファイルに記録した後 vi が終了して端末エミュレータに戻る。




3.3   emacs (p.152)

  emacs は編集時に特別なモードはなく、 入力したテキストはカーソルの位置にそのまま配置される。 また、カーソルの移動やいろいろなコマンドは、Ctrl や Meta キー と文字キーを同時に押して指定する。 キーボードによっては Meta キー が使えない/存在しない時がある。 その場合は、ESC キー を押して「から」文字キーを押すことにより代用する。

  以下が代表的なコマンドの入力方法である。
Ctrl-文字: Ctrl キー と文字キーを同時に押す
C-文字: 上記と同じ内容を表す
M-文字: Meta キー と文字キーを同時に押す、 または ESC キー を押して「から」文字キーを押す

  リージョンとは、文書中の一まとまりの領域で、 マークの位置からカーソルのある位置の前までがリージョンの範囲となる。

  操作を間違えた時、表示がおかしくなった時は、コマンドの中止 C-g を入力すると直る場合がある。


3.3.1   emacs の代表的なコマンド

○ 終了

C-x C-c : エディタの終了

○ コマンドの中止

C-g : 現在実行中のコマンドの中止

○ ファイルの読み込み/書き込み

C-x C-s : ファイルの保存
C-x C-w : 他のファイル名で保存
C-x C-f : ファイルを読み込む
C-x i : ファイルを挿入

○ ヘルプ

C-h t : 英語チュートリアルの表示
C-h T : 日本語チュートリアルの表示
C-h C-h : ヘルプ機能の一覧を表示

○ カーソルの移動

C-f : カーソルを一文字右に移動
C-b : カーソルを一文字左に移動
C-n : カーソルを一行下に移動
C-p : カーソルを一行上に移動
C-a : 行の先頭に移動
C-e : 行末に移動
C-v : 一画面下にスクロール
M-v : 一画面上にスクロール
M-< : 編集ファイルの先頭へ移動
M-> : 編集ファイルの末尾へ移動
C-s 文字列 : 文字列の検索
C-s で次候補
C-r で前候補

○ テキストの削除/移動/コピー

C-d : 一文字削除
C-k : 一行削除
DEL, BS : カーソルの前の文字を削除
C-Space : カーソル位置にマークを設定
M-h : カーソルのある段落をリージョンに指定する
C-x h : バッファ全体をリージョンに指定する
C-u C-Space : マークをつけた位置にカーソルを移動
C-x C-x : マークとカーソルの位置を入れ換える
C-w : リージョンを削除してカットバッファに記憶
M-w : リージョンを削除しないでカットバッファに記憶
C-k : カーソル位置より行末までを削除してカットバッファに記憶
M-k : 段落の終りまでを削除してカットバッファに記憶
C-y : カットバッファの内容をカーソル位置に挿入

○ ウィンドウの操作

C-x 2 : ウィンドウを上下に分割
C-x 5 : ウィンドウを左右に分割
C-x b : 編集ファイルの変更
C-x k : 編集ファイルから外す
C-x C-b : 編集ファイルの一覧を表示
C-x o : 他のウィンドウにカーソルを移す
C-x 0 : カーソルのあるウィンドウを消す
C-x 1 : カーソルのあるウィンドウだけにする


3.3.2   emacs の操作の実際

  以下では emacs を使用して文書を入力する時の典型的な操作の例を示す。
通常は編集対象のファイル(仮に sample.txt)を指定して起動する。
% emacs sample.txt
emacs はモードレスなので起動直後から文字入力とコマンド入力が随時可能である。 必要な文字を入力していき、必要に応じて編集コマンドを実行する。 一通り入力が終ったらファイルを記録して終了する。
Ctrl-x Ctrl-s でファイルに記録、
Ctrl-x Ctrl-c で emacs が終了して端末エミュレータに戻る。




3.4   日本語入力 (p.170)

  入力メソッドとして SCIM, 漢字変換システムとして Anthy という 二つのプログラムを組み合わせた日本語入力システムを使用する。 日本語に変換する時に使用するコマンドと、 コマンド表記の入力方法を以下に示す。
Ctrl-文字: Ctrl キー と文字キーを同時に押す
Shift-文字: Shift キー と文字キーを同時に押す

SCIM の代表的なコマンド

Ctrl-Space : 日本語入力の開始、停止
Space : 変換、次の候補
↑↓ : 変換候補の選択
← → : 文節の移動
Shift- ← : 文節の縮小
Shift- → : 文節の拡大


3.5   練習問題

  1. gedit で適当な文章を入力した後で、 gedit のコマンドを一通り実行して機能を確認しなさい。

  2. 数字とアルファベット 26 文字を並べた行 "0123456789abcdefg...xyz" を入力しなさい。

  3. gedit の選択範囲をコピーする機能を使って、上記の行を 100 行コピーしなさい。 それを ログインネーム-gedit.txt (例 ed04000-gedit.txt)として記録しなさい。

  4. 日本語入力の機能を使って、上記のファイルに自分の住所、学籍番号、 名前を記述しなさい。

  5. vi で適当な文章を入力した後で、vi の挿入コマンド、移動コマンド、 編集コマンドを一通り実行して機能を確認しなさい。

  6. アルファベット 26 文字と数字を並べた行 "abcdefg...xyz0123456789" を入力しなさい。

  7. vi のリージョンをコピーする機能を使って、上記の行を 100 行コピーしなさい。 それを ログインネーム-vi.txt (例 ed04000-vi.txt)として記録しなさい。

  8. 日本語入力の機能を使って、上記のファイルに自分の住所、学籍番号、 名前を記述しなさい。

  9. vi は挿入モードから直接終了することができるか ?

  10. vi はコマンドモードで文字入力が可能か ?

  11. vi でのキー入力'x'はモードによりどのように解釈されるか ?

  12. emacs で適当な文章を入力した後で、 emacs のコマンドを一通り実行して機能を確認しなさい。

  13. 数字とアルファベット 26 文字を並べた行 "0123456789abcdefg...xyz" を入力しなさい。

  14. emacs のリージョンをコピーする機能を使って、上記の行を 100 行コピーしなさい。 それを ログインネーム-emacs.txt (例 ed04000-emacs.txt)として記録しなさい。

  15. 日本語入力の機能を使って、上記のファイルに自分の住所、学籍番号、 名前を記述しなさい。

  16. gedit, vi または emacs でどれが最も使い易いと感じたか、その理由を文書にしなさい。 その後に続けて、 選択したエディタの主要な機能を自分が読んでわかるようにまとめて記述しなさい。 ファイル名は ログインネーム.txt (例 ed04000.txt)とする。

  17. GUI 環境でマウスを併用する Word, gedit などと、CUI 環境の vi, emacs について, それぞれの長所、短所を考えて上記のファイルに記述しなさい。





4   UNIX, Linux の特徴 (第 2, 3 週)


4.1   UNIX, Windows の特徴と相違点 (p.22)

  UNIX の特徴として以下の事柄を挙げることができる。

  対する Windows の特徴として以下の事柄がある。

  両者の相違点として様々なものがあるが、特に操作性の点では UNIX は初心者には使い難く Windows は初心者でもある程度練習すれば使えるようになる。 一方熟練者にとっては UNIX は効率良く作業を行なう仕組みが豊富に用意されているが、 Windows にはそのような仕組みがあまりないといえる。 これらは何を重視するかにより生じている違いであり、それぞれの長所であり短所となっている。



4.2   Login, Logout (p.36)

  UNIX, Linux は 1 台のコンピュータを複数のユーザが(必要であれば同時に) 使うことを前提として開発されているので、 「誰が」使用するかを必ず入力して個人認証を行う。 この操作を Login (Logon) と呼ぶ。作業を終了する時にはそのことを OS に通知する。 この操作を Logout (Logoff) と呼ぶ。



4.3   一般ユーザと特権(管理者)ユーザ (p.38)

  UNIX, Linux のユーザ、使用者は、操作可能なコマンドやアクセス可能なファイル、 デバイスが異なる、一般ユーザと特権(管理者)ユーザに分かれる。 UNIX における特権(管理者)ユーザは標準的な名前 root と呼ばれる。

  これらのユーザの違いは OS に対して持っている権限の違いと言える。 一般ユーザは通常の作業をするには十分な権限を持つが、 OS の重要な部分やファイルを操作する権限はない。 これにより、不注意や知識の不足による誤操作でシステムを壊してしまう恐れがなくなる。

  特権(管理者)ユーザは、システムのあらゆる部分を操作できるが、 万一誤操作をすると簡単にシステムを壊してしまうことになる。 よって、特権(管理者)ユーザであっても、通常の仕事は必ず一般ユーザで行なう。

例
一般ユーザは重要なファイル、他人のファイルを見ることができない。
一般ユーザはシステムの動作に関連するファイルを消すことができない。
一般ユーザはデバイスを直接操作できない。
一般ユーザは OS を停止できない。
一般ユーザは特権(管理者)ユーザになれない。


4.4   パスワード (p.36,59)

  個人認証では、使用する前にパスワードを入力させて登録された本人か確認する。 パスワードとはユーザがあらかじめ登録している数文字の文字列で、 本人しか知らない。本人しか知らないパスワードを正しく入力できれば、 本人と見なされる。よってパスワードは他人に知らせてはいけない。 パスワードは暗号化されて所定のファイルに記録されている。



4.5   シェル, Shell (p.64,115)

  標準的なユーザインタフェースとして、キャラクタベースの「シェル」を使用する。 シェルを通して OS にコマンドの起動や様々な指示を与えることで作業を進める。 マウスを使わないで、キーボードから入力する文字ですべての指示を与えるため、 離れた場所のコンピュータをネットワーク経由で使うことができる。

例
% ssh luna.edu.isc.chubu.ac.jp


4.6   コマンド (p.45,66)

  UNIX, Linux では多数のコマンドが標準で付属する。 個々のコマンドは比較的単純な機能しか持たず、単一のコマンドで複雑な処理はできない。 そのかわりに、各コマンドは他のコマンドと組み合わせて使用できるように、 データの入力、出力の仕組みが統一されている。複雑な処理を実現したいときは、 様々なコマンドを組み合わせて実現するのが一般的である。

例
ある日(仮に 10 月 3 日とする)、何人のユーザがこのコンピュータを
使用したか調べたいとする。利用者の記録は
% last
で調べることができる。
このコマンドに文字列検索のコマンド、
行数を数えるコマンドを組み合わせて、
% last | grep 'Oct  3' | wc -l
で回数が分かる。更に、
% last | grep 'Oct  3' | cut -f 1 -d ' ' | uniq | sort
とすると、重複した行を削除して正しい人数がわかる。
(※ Oct と 3 の間は空白文字が 2 個必要)


4.7   man, オンラインマニュアル (p.40,82)

  UNIX, Linux では豊富なオンラインマニュアルを備えており、 わからないことはまずオンラインマニュアルで調べる。使用方法は、
% man 調べたい事柄
と入力する。調べたい事柄にはコマンドの名前、C 言語の関数名、 設定ファイル名などが指定できる。 man コマンドで次のページを見たい場合は、Enter や Space を入力する。 上下の矢印キーでも移動可能。終了は 'q' を入力する。

例
% man ls	コマンド ls の機能や使い方を調べる
% man cat	コマンド cat の機能や使い方を調べる
% man printf	C 言語の関数 printf() の機能や使い方を調べる
% man hosts	/etc/hosts 設定ファイルの機能や記述の仕方を調べる


4.8   練習問題

  1. Windows と UNIX, Linux との違いを何点か挙げなさい。

  2. login, logout が必要な理由を考えなさい。

  3. 一般ユーザと管理者ユーザが存在する理由を考えなさい。

  4. パスワードを決める際に気をつけることを考えなさい。

  5. パスワードの取り扱いで気をつける点を挙げなさい。

  6. UNIX のシェルはキーボードからの文字入力だけですべての操作ができるが、 それによりどのような利点があるか考えなさい。

  7. Windous の標準的なユーザインタフェースである、ビットマップディスプレイ、 マウス、アイコンやメニューを使用する GUI (Graphical User Interface) と、 UNIX, Linux の CUI (Character User Interface) について、それぞれの長所、 短所を考えなさい。

  8. 4.6 の例の日付を講義当日に変更して実行しなさい。その結果から、 その日に login した合計回数と人数を求めなさい。

  9. 4.7 の説明にしたがって、コマンド ls, cat, date, cal の機能をオンラインマニュアルを利用して調べなさい。





5   データを記録、参照する仕組 (第 4, 5 週)


5.1   ファイルとディレクトリ (p.72,87)

  多くの OS では、コンピュータ上で扱うデータを記録、 操作する単位はファイルと呼ばれる概念で表される。

  ファイルを記録する場合に管理を容易にするためにディレクトリという仕組みが利用される。 ディレクトリは複数のファイルをまとめて一つの場所に置いておくことができる。 ファイルを整理したい条件に合わせて様々なディレクトリを用意して、 その中にファイルを記録する。

例
% ls /usr8/ed04
ed04001  ed04014  ed04030  ed04046  ed04058  ed04071  ed04083  ed04097  ed04109
ed04002  ed04016  ed04031  ed04047  ed04059  ed04072  ed04084  ed04098  ed04110
ed04003  ed04018  ed04032  ed04048  ed04060  ed04073  ed04086  ed04099  ed04111
ed04004  ed04019  ed04033  ed04049  ed04061  ed04074  ed04087  ed04100  ed04112
ed04005  ed04021  ed04035  ed04050  ed04062  ed04075  ed04088  ed04101
   .
   .
以下略
  この例では 2004 年度入学の ed の学生が使用する個人用ディレクトリがまとめて登録されている /usr8/ed04 という架空のディレクトリを例として表示している。 / の下に usr8 があり、その下に ed04 があり、その下に個人用の ed04001, ed04002, ... があり、 複数の階層にわかれて管理されていることがわかる。

% ls /usr
X11    bin   dpt  games    kerberos  libexec  opt   share  tmp
X11R6  dict  etc  include  lib       local    sbin  src
  この例では / の下に usr というディレクトリがあり、その下のディレクトリが表示されている。 これらはすべて OS が管理、使用している領域で、各種プログラムや文書、設定ファイルなどが 様々なディレクトリに分かれて保存されている。



5.2   パス : ファイルの位置 (p.56,87)

  ファイルやディレクトリの位置を表す情報をパスと呼ぶ。パスには / (ルート ディレクトリ) からの位置を表す絶対パスと、現在のディレクトリ位置を起点 として表す相対パスがある。

  よく使われる表記法として . は現在のディレクトリを、.. は一つ上の階層のディレクトリを、 ~ はホームディレクトリを表す。

  ホームディレクトリに戻る場合は次のどれかのコマンドを実行する。
% cd ホームディレクトリの絶対パス指定
% cd ホームディレクトリの相対パス指定
% cd ~
% cd


  / は最上位のディレクトリ(ルートディレクトリ)を表す。 例として、現在のディレクトリが /usr8/ed04/ed04000 とすると (実際のディレクトリは % pwd で確認できる)、 /, usr8, ed04, ed04000 という 4 段階の階層構造になっている。 一つ上の階層は、絶対パスなら /usr8/ed04 となり、相対パスなら .. となる。 二つ上の階層は、絶対パスなら /usr8 となり、相対パスなら ../.. となる。 三つ上の階層は、絶対パスなら / となり、相対パスなら ../../.. となる。

  現在のディレクトリが /usr8/ed04/ed04000 の場合、 別の年度の学生のディレクトリ /usr8/ed05/ed05000 は、 絶対パスならそのまま /usr8/ed05/ed05000 と表せ、 相対パスなら ../../ed05/ed05000 と表すことができる。

  /usr は / の下の usr というディレクトリ(またはファイル)を表す。 usr がディレクトリかファイルかは名前を見ただけではわからないが、 属性を表示させてみるとわかる。
% ls -l /
を実行すると、多くの表示の中に
drwxr-xr-x 16 root root 4096 9月 25 15:42 usr/
と表示されるが、左端の d がディレクトリであることを表している。 もし通常のファイルであれば、
-rwxr-xr-x 16 root root 4096 9月 25 15:42 usr/
のように - が表示される。

  以下はディレクトリを絶対パス、相対パスで指定して移動するコマンド指定の例である。 実際に試す時は usr8 や ed04 を実在するディレクトリに置き換える必要がある。

例
% pwd			現在のディレクトリを表示するコマンド
/usr8/ed04/ed04000
% cd ../../..		上の上の上に移動、cd はディレクトリを移動するコマンド
% pwd
/			ルートディレクトリに移動したことがわかる
% cd ./usr8/ed05	相対パスで指定して、現在のディレクトリ下の usr8/ed05 に移動
% pwd
/usr8/ed05
% cd ../ed04/ed04000	相対パスで指定して、一つ上の階層にある ed04/ed04000 に移動
% pwd
/usr8/ed04/ed04000	もとに戻った
% cd /etc		絶対パス、/etc に移動
% pwd
/etc
% cd /usr8/ed04/ed04000	絶対パス指定
% pwd
/usr8/ed04/ed04000	もとに戻った
  UNIX, Linux では OS を動作させるのに必要なファイルを、 標準的な名前の様々なディレクトリに記録している。 各ディレクトリの名前は UNIX 系の OS ではほぼ同じになっている。

  UNIX, Linux では通常のデータを記録するファイルの他に、 周辺装置もファイルと同じ形式で表現され、操作できるようになっている。



5.3   ファイルの属性、アクセス制限 (p.92)

  UNIX, Linux のファイル、ディレクトリは保護機能がしっかりしており、 誰がファイルを読めるか、書き込めるか、実行できるかという点を厳密に管理している。

  以下の例はあるディレクトリでファイルの一覧を表示するコマンド 'ls -l' を実行した時の出力である。 左端の drwx------ などの表示がファイルアクセスの設定を表している。

% ls -l
合計 100
drwx------    2 naga     denshi2      4096  7月 24  2001 2001list
drwx------    2 naga     denshi2      4096  7月 24  2002 2002list
-rw-r--r--    1 naga     denshi2       108  4月 23  2003 README
drwx------    2 naga     denshi2      4096  7月 24  2002 bin
-rw-------    1 naga     denshi2      9311  7月  4  2000 chubu2000.txt
-rw-------    1 naga     denshi2      1062  7月  4  2001 chubu2001.txt
-rw-r--r--    1 naga     denshi2       308  4月 30  2003 howtocopy
-rw-r--r--    1 naga     denshi2      4813  5月 14  2003 index.html
drwx------    2 naga     denshi2      4096  4月 16  2003 tmp
   .
   .
以下略
  左から順に、ファイルモード(アクセス制限)・リンク数・所有者名・所有グループ名・ ファイルのバイト数・最終更新時の月・日・時・分(または年)・パス名(ファイル名)を表す。 最後の行を例として用い、各フィールドの表す内容を以下に示す。

drwx------    2 naga     denshi2      4096  4月 16  2003 tmp
   (1)      (2)  (3)       (4)         (5)  (6) (7)  (8) (9)
  以下は /etc に対してファイルの一覧を表示するコマンド 'ls -l' を実行した時の出力である。

% ls -l /etc
合計 2064
-rw-r--r--    1 root     root         2456  8月 13  2003 DIR_COLORS
-rw-r--r--    1 root     root         2434  8月 13  2003 DIR_COLORS.xterm
drwxr-xr-x    4 root     root         4096  7月 14  2004 FreeWnn
drwxr-xr-x   16 root     root         4096  2月 15  2005 X11
-rw-r--r--    1 root     root         2562  1月 25  2003 a2ps-site.cfg
-rw-r--r--    1 root     root        15228  1月 25  2003 a2ps.cfg
-rw-r--r--    1 root     root           46  8月 28 18:05 adjtime
   .
   .
以下略
  この例では、最下行の adjtime の最終更新時刻が最近だったため、 年の代わりに時刻が表示されている。


5.3.1   アクセス権、アクセス制限の詳細

  UNIX, Linux では個々のユーザはどれかのグループに所属すると決められている。 グループの例として管理者のグループ、一般ユーザのグループ、 ゲストのグループなどが考えられる。所属するグループは一つでも複数でもよい。

  ファイルのアクセス権、アクセス制限は各ファイルの所有者(ユーザ)、所有グループ、 その他のユーザの 3 種類に分けて設定される。 所有者の他に所有グループという分類があるのが特徴である。 アクセス権、アクセス制限は「パーミッション」と呼ばれることもある。

  ここまでの説明中、「drwx------ がアクセス権、アクセス制限を表し、左から 2 文字目以降は 3 文字ずつがペアになり、ファイルの所有者、所有グループ、 その他のユーザのアクセス制限を表す。」という内容の記述があったが、 以下ではその詳細を示す。

  drwx------ は、(1) d, (2) rwx, (3) ---, (4) --- という 4 個の部分に分解できる。 (1) の d はファイルの種類を示しているのでアクセス権には関係ない。 (2) の rwx はこのファイルを所有するユーザがどのようなアクセスが可能か示している。

  r はこのファイルを読出す権利を持つ、w はこのファイルに書込む権利を持つ、 x はこのファイルを実行する権利を持つことをそれぞれ表す。 実行権については、ディレクトリの場合はコマンド cd で移動することが可能、 通常ファイルについては実行できる内容を持つファイルであれば実行できることを表す。

  (3) の --- は各文字が読出権、書込権、実行権を表しているのは同じだが、 - になっているのでこのファイルを所有するグループのユーザには いずれも許可されていないことを表す。 (4) も同様にすべて不許可を表し、その他のユーザはアクセスできないことを表す。

  まとめると、このファイルの所有者は読出権、書込権、実行権をすべて有しているが、 所有するグループのユーザ、およびその他のユーザは一切アクセスできないことを表している。

  以下ではアクセス権の設定例をいくつか示す。

アクセス権の設定、変更は(次の章で出てくる)コマンド chmod で行なう。
アクセス制限は 3 桁の 8 進数で表現する。
例として、file1 を -rwxr-xr-x に設定したい場合は、
% chmod 755 file1
file2 を -rwx------ に設定したい場合は、
% chmod 700 file2
file3 を -rw-r--r-- に設定したい場合は、
% chmod 644 file3
となる。



5.4   練習問題

  1. 現在のディレクトリを表示するコマンド行を示しなさい。

  2. /usr/bin に絶対パス指定で移動するコマンド行を示しなさい。

  3. ホームディレクトリに戻るコマンド行を示しなさい。

  4. /usr/bin に相対パス指定で移動するコマンド行を示しなさい。

  5. ホームディレクトリに相対パス指定で戻るコマンド行を示しなさい。

  6. ホームディレクトリに絶対パス指定で戻るコマンド行を示しなさい。

  7. ホームディレクトリから別の学年のディレクトリ ed06 に相対パス指定で移動するコマンド行を示しなさい。

  8. ホームディレクトリから別の学年のディレクトリ ed06 に絶対パス指定で移動するコマンド行を示しなさい。

  9. /usr/share/man/man1 に、 ホームディレクトリからの相対パス指定で移動するコマンド行を示しなさい。

  10. cd /usr/share/doc を実行後に、/usr/share/man/man1 に相対パス指定で移動するコマンド行を示しなさい。

  11. -r-xr-x--- はどのようなアクセス制限を表すか説明しなさい。

  12. drwxr-x--- はどのようなアクセス制限を表すか説明しなさい。

  13. 所有グループに属する人は誰でも読み書きできる設定を示しなさい。

  14. 所有者は読み書き実行可能、 所有グループとその他のユーザは読み出しのみ可能な設定を示しなさい。

  15. ホームディレクトリにあるファイルのアクセス権の設定を調べなさい。

  16. 各回にファイルを提出するディレクトリ /usr7/denshi2/naga/午前午後/日付 のアクセス権の設定を調べなさい。

  17. エディタで何かファイル(仮に sample とする)を作成し、chmod 000 sample, chmod 400 sample, chmod 600 sample, chmod 700 sample のようにアクセス権を いろいろ設定しなさい。 それぞれの場合でエディタで開くことや書き換えが可能か試してみなさい。

  18. UNIX システムの標準的なディレクトリ /bin, /usr, /etc, /tmp, /var, /home の用途を調べなさい。(教科書 p.53〜)

  19. /bin, /etc, /dev 中のファイルの所有者、アクセス権の設定を調べなさい。 なぜそのような設定になっているか理由を考えなさい。





6   コマンド (第 6, 7 週)


6.1   凡例

  以下の記述で、[, ] で囲まれている部分は省略可能、書いても書かなくてもよいことを表す。 例として % mkdir dir [dir2 ...] の場合、
% mkdir dir
と指定すれば dir だけを作成し、
% mkdir dir dir2 % mkdir dir
と指定すれば dir と dir2 の 2 個のディレクトリを同時に作成できることを表す。

  file, file2 などはファイルを、dir, dir2 などはディレクトリを表す。 コマンドを実行する時は実在するファイルやディレクトリで置き換える。



6.2   UNIX の代表的なコマンド


6.2.1   ディレクトリ操作 (p.103)

cd : 指定したディレクトリに移動する。
% cd dir
% cd				// ホームディレクトリに移動

mkdir : ディレクトリを作成する。
% mkdir dir [dir2 ...]

rmdir : ディレクトリを削除する。
% rmdir dir [dir2 ...]

pwd : 現在のディレクトリを表示する。
% pwd


6.2.2   ファイル操作 (p.91,96)

ls : ファイルの一覧を表示する。
% ls
% ls -Flg -a dir		// ファイルの詳細を表示

mv : ファイル/ディレクトリを移動する、名前を変更する。
% mv file file2			// ファイル名の変更
% mv file dir/file2		// ファイルを dir に移動して、ファイル名の変更
% mv file [file2 ...] dir	// ファイルを dir に移動
% mv dir dir2			// dir を dir2 に移動、または名前の変更
※ 最後に書くのがファイル名だけだと名前の変更、別のディレクトリとファイル名を
   指定すると移動と名前の変更を同時に行なう。ディレクトリだけだと移動。
   最後の例では、dir2 が既存なら移動、存在しなければ名前の変更になる。

cp : ファイルをコピーする。
% cp file file2			// file を file2 という名前でコピー
% cp file [file2 ...] dir	// file を dir にコピー
% cp -R dir [dir2 ...] dir3	// dir の中身も一緒に dir3 にコピー

rm : ファイルを削除する。
% rm file [file2 ...]
% rm -r dir [dir2 ...]		// dir の中身も一緒に削除
% rm -i file			// 対話的に確認しながら削除

find : ファイルを探して指定した処理をする。
% find dir -name "*.txt" -print		// 条件に合うファイルの名前を表示

chmod : ファイルのアクセス権を設定する。
% chmod 644 file
% chmod u+rw,go=r-wx file	// 8 進数以外にこのような記法もある。man chmod を見よ。

file : ファイルの種類を表示する。
% file file2 [file3 ...]	// 最初の file はコマンド名、この例では file2 の
				// 種類を表示する。

whereis : ファイルの場所を探す。
% whereis ls			// コマンド ls のある場所を表示
% whereis -m cat		// コマンド cat のマニュアルのある場所を表示

touch : ファイルのアクセス時刻と変更時刻を変える。
% touch file			// file のアクセス日時を更新、存在しなければ新規作成
% touch -t 200510011234 file	// アクセス日時を指定した値にする


6.2.3   テキストファイル操作 (p.96,103)

cat : ファイルを表示、縦方向に連結する。
% cat file 			// file の内容を画面に出力する。
% cat file [file2]		// file2 を指定した場合は file に続けて出力する。

more : ファイルを 1 画面分ずつ表示する。
% more file

less : ファイルを 1 画面分ずつ表示する。後戻りが可能。
% less file

head : ファイルの先頭を表示する。
% head file

tail : ファイルの末尾を表示する。
% tail file

diff : 2 個のファイルの違いを調べる。
% diff file file2

grep : ファイルから指定した文字列を検索する。
% grep abc file			// file から abc という文字列を含む行を探して表示する。
% grep 'abc def' file		// "abc def" という文字列を対象にする

wc : ファイルのバイト数、語数、行数を数える。
% wc file			// file のバイト数、語数、行数を表示する。
% wc -l file			// file の行数を表示する。

uniq : ファイル内の重複行を調べて削除する
% uniq file

cut : ファイルから指定した部分を取り出す。
% cut -f 1 -d ' ' file		// 空白文字を区切り文字として、各行の 1 番目の項目を取り出す
% cut -b 1-10 file		// 各行の最初の 10 バイトを取り出す

paste : ファイルを横方向に連結する。
% paste file file2

sort : ファイルの内容を指定した項目により並び換える。
% sort file
% sort -k 2 file		// 左から 2 番目の項目を基準に並び換える。
% sort +1 file			// 左から 2 番目の項目を基準に並び換える。このような書き方も可能。
% sort -n file			// 先頭の項目を数値として小さい順に並び換える。
% sort -b file			// ソートする項目の先頭にある空白を無視する。
% sort -r file                  // 並び換えの順序を逆にする。

tr : 文字列を置換、削除する
% echo abcdefg | tr abc ABC	// 試してみよう
% echo abcdefg | tr -d abc
% cat file | tr abcdefghijklmnopqrstuvwxyz opqrstuvwxyzabcdefghijklmn > file2
% cat file2
※ ファイルの暗号化
% cat file2 | tr opqrstuvwxyzabcdefghijklmn abcdefghijklmnopqrstuvwxyz > file3
% cat file3
※ 暗号化されたファイルの復号化

sed : テキストデータを処理する非対話的なエディタ
% echo abcdefg | sed s/abc/123/ // 試してみよう


6.2.4   ユーティリティ (p.177)

df : ディスクの使用量を表示する。
% df

du : ファイル、ディレクトリのディスク使用量を表示する。
% du

look : 指定した文字列を辞書から検索する。
% look word			// word が辞書に登録されているか調べる。

man : オンラインマニュアルを表示する。
% man ls
% man 2 intro

passwd : パスワードを変更する。
% passwd

w : ログインしているユーザと、作業内容を表示する。
% w

who : ログインしているユーザを表示する。
% who

whoami :  自分が誰かを表示する。
% whoami

yes : 指定した文字列を連続して出力する。
% yes				// y を無限に出力する
% yes 'Hello world.'		// Hello world. を無限に出力する
% yes | rm -i *.txt		// rm -i の確認に y を答え続ける

uptime : システムの稼働時間を表示する。
% uptime

last : 最近ログインしたユーザの記録を表示する。
% last

date : 日付と時刻を表示する。
% date

cal : カレンダーを表示する。
% cal				// 現在の月のカレンダーを表示する。
% cal 10 2005			// 2005 年 10 月のカレンダーを表示する。

at : 指定した日時にプログラムを実行する。
% echo "ls" | at 20:14		// 20:14 に ls を実行する (セキュリティの関係で試せない)
% echo "ls" | at 20:14 101805

bc : 数値計算をする。
% echo "scale=10; 1+2*4/3" | bc -l	// 試してみよう
% echo "scale=10; s(3.1416/2)" | bc -l	// sin(pi/2) の表示
% echo "scale=10; 4*a(1)" | bc -l	// 試してみよう


6.2.5   プロセス制御 (p.192)

kill : プロセスに様々なシグナルを送る。
% kill pid
% kill -HUP pid			// ハングアップシグナルを送る
% kill -KILL pid		// 強制終了のシグナルを送る

ps : プロセスの状態を表示する。
% ps -Al
% ps aux

top : 現在実行中のプロセスに関する情報を表示する。
% top



6.3   練習問題

  1. 上記のコマンドからいくつかを選んで、 オンラインマニュアルを利用しての代表的な機能を調べなさい。 調べた結果を簡潔にまとめて説明しなさい。 実際にそれらの機能を使用してみなさい。

  2. 次に示す機能を実現するコマンドの組み合わせを考えなさい。cat.txt, data.txt, data2.txt, last.txt, ps.txt は指定されたディレクトリからコピーしなさい。
    1. tmp1, tmp2, tmp3, tmp4 というディレクトリを作成する

    2. tmp1 の中に sample1、tmp3 の中に sample3 というファイルを作成する

    3. tmp2 を削除する

    4. tmp3 を削除する

    5. tmp1/sample1 を sample2 というファイル名でコピーする

    6. sample1, sample2 を tmp4 に移動する

    7. sample2 のファイル名を sample3 に変更する

    8. tmp4/sample1,3 を tmp1 にコピーする

    9. ホームディレクトリ以下でファイル名が sample で始まるものを探して表示する

    10. sample1 のパーミッションを自分は読み書き実行可能に、 それ以外はすべて不許可に設定する

    11. sample3 のパーミッションを自分は読み書き実行可能に、 それ以外は読み出しだけ可能に設定する

    12. /etc/hosts のファイルの種類を調べる

    13. コマンド cat がある場所を調べる

    14. cat.txt, ps.txt を縦に連結して表示する

    15. cat.txt, ps.txt を横に連結して表示する

    16. cat.txt を一画面分ずつ表示する

    17. cat.txt の先頭を表示する

    18. cat.txt の末尾を表示する

    19. data.txt, data2.txt の違いを調べる

    20. data.txt 中に "5678" という文字列を含む行が何行あるか調べる

    21. cat.txt 中に "the" という文字列を含む行が何行あるか調べる

    22. data.txt が何行あるか調べる

    23. ps.txt から第 1 列のユーザ名だけを取り出す

    24. ps.txt に何人のユーザが含まれるか調べる

    25. ps.txt を PID の順番に並べ換える

    26. tr を使って cat.txt を暗号化する

    27. tr を使って暗号化された cat.txt を復号化する

    28. 過去に誰が login したか調べる

    29. 起動してからの稼働時間を表示する

    30. UNIX システムでいくつのプロセスが並行して動いているか調べる

    31. cat.txt の小文字をすべて大文字に変換する

    32. HDD の使用状況を調べる

    33. 自分が占有しているディスクの容量を調べる

    34. 単語 "organisation" の綴りが正しいか調べる

    35. 自分のマシンに誰がログインしているか調べる

    36. 10 分後にカレンダーを表示する。(現在試すことはできない)

    37. sin(30deg) の値を求める





7   シェルによる操作環境 (p.115) (第 8, 9 週)

  UNIX, Linux で標準的なユーザインタフェースとして使用されるシェルには様々な種類がある。 広く使われている代表的なシェルとして bash, tcsh がある。 これらは古くからある bsh(sh), csh の機能を拡張して新しく作られた。 実習用の環境では tcsh が標準のシェルとして設定されている。 以下では tcsh の代表的な機能を順に解説する。


7.1   コマンドラインの編集、文字列補完 (p.144)

例
% sl /usr/share/man/man1
と入力したところでコマンド名の間違いに気がついたら
Ctrl-a や Ctrl-p でカーソルを戻して修正できる。

% bindkey
で編集コマンドの確認ができる。

% set correct = all
% ls /usr/share/ma
まで入力して TAB キーを押すと補完がされる。
補完がされない時は Ctrl-d を入力すると候補が表示される。

% set autocorrect
% sl /usr/share/man/man1
と入力して RET キーを押すと、
CORRECT>ls /usr/share/man/man1 (y|n|e|a)?
と教えてくれる。
% sl /usr/share/mann/man1
でも大丈夫。


7.2   ファイル名の置換、字句解析 (p.143)

  コマンドラインからファイル名を指定する場合、次の文字 *, ?, [, ], ~ は特殊な意味を持ち、これらを活用することでファイル名を簡潔に指定できる。

例
/usr には以下のファイル、ディレクトリがある。
% cd /usr
% ls
X11    bin   dpt  games    kerberos  libexec  q!    share  tmp
X11R6  dict  etc  include  lib       local    sbin  src

% ls -d X*
X11  X11R6

% ls -d ???
X11  bin  dpt  etc  lib  src  tmp

% ls -d [a-e]*
bin  dict  dpt  etc

% ls ~/[a-z]*
ホームディレクトリの a 〜 z で始まるファイル、
ディレクトリが表示される


7.3   エイリアス (p.145)

  エイリアスとはコマンドに別名を付ける機能で、長いコマンド、 複雑なコマンドに短いわかりやすい名前を付けたり、 頻繁に指定するオプションを含めて新しい名前を付ける時に使用する。

  エイリアスの設定は以下の例に示すように、シェルの組み込みコマンド alias を使って、 alias 新しい名前 古い名前の順に指定する。 古い名前には複数の文字列を指定でき、オプションなどを含めることができる。

例
% alias
alias   a       alias
a       h       history
a       more    less
a       ls      ls -F
a       ll      ls -l
a       la      ls -a
a       cls     clear
a       lo      logout
a       l       look
a       gv      ghostview
a       sc      source $HOME/.cshrc
a       ?       whereis
  エイリアスの設定を削除する時は unalias エイリアス名とする。

例
% unalias a


7.4   ヒストリ (p.141)

  ヒストリはシェルから実行したコマンドの履歴を記録しておく機能で、 必要に応じて一覧を表示したり、過去に実行したコマンドを簡単な指定で再度実行できる。

  シェルの組み込みコマンド history を実行すると、 過去に実行したコマンドの履歴を表示できる。 以下では history の出力例と、様々な方法で履歴中のコマンドを指定する方法を示す。

例
% history
     1  18:41   emacs softa.xml
     2  20:03   lo
     3  15:09   h | grep startx | wc -l
     4  15:09   h | grep lo | wc -l
     5  15:09   h | more
     6  15:27   sc
     7  15:28   cat .history
     8  19:53   startx
     9  22:11   more .history
    10  22:13   ? ls
    11  22:13   su
    12  22:13   exit
    13  18:37   rsh farm from
    14  18:37   ssh farm
    15  18:41   cd xml

% !!	// 直前に実行したコマンドを指定する。
cd xml


% !7	// ! と数値を指定することで履歴中のコマンドを指定する。
cat .history

% !c	// ! とコマンドの先頭の数文字を指定して、
        // 該当する文字から始まるコマンドを指定する。
cd xml

% !ca
cat .history
ファイル .history の内容が表示される。

% Ctrl-p 	// Ctrl-p, Ctrl-n で履歴中のコマンドを逆/順方向に
                // たどって呼び出すことができる。
% cat .history
が表示され、再度 Ctrl-p を入力すると

% cd xml

が表示される。自分が呼び出したいコマンド、近いコマンドが
表示されたら適宜編集してEnter で実行できる。


7.5   シェル変数 (p.139)

  シェル変数とはプログラミング言語における変数のような機能で任意の変数名と値を設定できる。 シェルではシェルスクリプト(プログラミング言語)により、 使用者が様々なコマンドや機能を組み合わせて複雑な処理を登録、実行することができる。 シェル変数はシェルスクリプト中で変数として設定、参照ができる。

  シェル変数はあらかじめ名前と機能が定義されているものがあり、 シェルの動作や機能を設定するのに使用される。

シェル変数の設定状況はシェルの組み込みコマンド set で確認する。
% set

シェル変数の設定は
% set 変数名
または
% set 変数名 = 値
とする

シェル変数の設定の削除は
% unset 変数名
とする
  シェルが自動的に設定するシェル変数は様々なものがある。 以下ではあらかじめ名前が登録されている、 特別な意味を持ったシェル変数の代表的なものを示す。

autocorrect    コマンドラインでのコマンド名やファイル名の自動修正
cdpath         cd が探索すべきディレクトリのリスト
correct        コマンドラインでのスペル訂正の設定、値は cmd, complete, all
cwd            カレントディレクトリのフルパス名
edit           コマンドラインエディタ、対話型シェルではデフォルトで設定される
gid            ユーザの実グループ ID
group          ユーザのグループ名
history        記録しておくヒストリイベント数
home           起動したユーザのホームディレクトリ、~ の展開に参照する
ignoreeof      Ctrl-d でシェルを終了しない設定
noclobber      ファイルを壊さないための、出力リダイレクションの制限
path           実行可能なコマンドを探すディレクトリのリスト
uid            ユーザの実ユーザ ID。
user           ユーザのログイン名。


7.6   環境変数 (p.136)

  環境変数はシェル変数とよく似た機能で任意の変数名と値を設定できる。 シェル変数と異なる点は、変数の値をシェルが定義したり参照するだけでなく、 そのシェルから起動されたプログラムに変数名と値が通知される点である。 よって環境変数を使うと、シェルから起動されたプログラムは、 実行される環境に関する様々な設定や情報を知ることができる。 様々な実行プログラムに関する設定をシェルの定義ファイルで統一して管理するために使用される。

  環境変数もあらかじめ名前と機能が定義されているものがあり、 シェルの動作や機能を設定するのに使用される。

環境変数の設定状況はシェルの組み込みコマンド printenv で確認する。
% printenv

環境変数の設定は
% setenv 変数名
または
% setenv 変数名 値
とする

環境変数の設定の削除は
% unsetenv 変数名
とする
  シェルが自動的に設定する環境変数は様々なものがある。 以下ではあらかじめ名前が登録されている、 特別な意味を持った環境変数の代表的なものを示す。

GROUP          group シェル変数と同じ
HOME           home シェル変数と同じ
HOST           シェルが実行されているマシンの名前
HOSTTYPE       シェルが実行されているマシンのタイプ、この変数は廃止される予定
LANG           優先的に使用される文字環境
MACHTYPE       コンパイル時に決定されたマシンタイプ
OSTYPE         コンパイル時に決定されたオペレーションシステム
PATH           実行可能ファイルを探すディレクトリ
PWD            シェル変数 cwd に似てい
TERM           term シェル変数と同じ
USER           user シェル変数と同じ
VENDOR         コンパイル時に決定されたベンダ名
  環境変数をプログラムから読み出す場合は、 次のように文字列として読み出して必要な値を取り出す。

// gcc -o env env.c

#include	<stdio.h>

int     main(int argc, char **argv, char **envp)
{
    int		i;

    for (i = 0; NULL != envp[i]; i++) printf("%s\n", envp[i]);

    return(0);
}


7.7   設定ファイル .cshrc, .login (p.147)

  シェル変数、環境変数、エイリアス、実行可能ファイルを探すパスの設定などは手動でも可能だが、 特定のファイルに記録しておくことでシェルの起動時に自動的に読み込ませることができる。 シェルの種類毎にファイル名が決まっているが、.cshrc, .tcshrc, .bashrc などがある。 また login した時の固有の設定を指定するための .login というファイルもある。



7.8   標準入出力、リダイレクト、パイプ (p.118,122)

  UNIX, Linux の下で実行されるプログラム(コマンドを含む)には、 プログラムが処理対象のデータを外部から読み込む(入力する)対象と、 処理結果を外部に出力する対象として、標準入力、 標準出力と呼ばれる仕組みが用意される。 通常、標準入力にはキーボード、標準出力にはディスプレイが割り当てられているが、 それぞれ設定によって変更することもできる(リダイレクト)。 以下は標準入出力の機能の確認をするプログラムである。

例
// gcc -o io io.c

#include	<stdio.h>

int	main(void)
{
    int		i, j;

    scanf("%d", &i);
    scanf("%d", &j);
    printf("%d\n", i + j);
    return(0);
}

上記のプログラムをコンパイルして実行する。
% ./io
適当な数値を 2 行に分けて「キーボード」から入力すると、
3
5
加算した結果が「ディスプレイ」に表示される。
8
  標準入力、標準出力を通常設定されているキーボード、ディスプレイ以外に振り向ける、 割り当て直す操作を「リダイレクト」という。 標準入力は 「<」 で、標準出力は 「>」 または 「>>」 でファイル、 その他の装置に変更できる。

例
入力するデータをあらかじめエディタでファイルに書き込んでおく。
% vi (または emacs) number.txt
% cat number.txt
5
7
このファイルを上記のプログラム io にリダイレクトの機能を使って入力すると
% ./io < number.txt
結果が表示される。
12

またリダイレクトの機能で結果をファイルに書き込むこともできる。
% ./io < number.txt > result.txt
% cat result.txt
12

次のように指定すると既存のファイルに結果を追記することもできる。
% ./io < number.txt >> result.txt
% cat result.txt
12
12
  あるプログラムの標準出力を別のプログラムの標準入力に接続する仕組みを 「パイプ、パイプライン」という。パイプは縦棒「 | 」で指定する。

例
// gcc -o io2 io2.c

#include	<stdio.h>

int	main(void)
{
    int		i;

    scanf("%d", &i);
    printf("%d\n", i + i);
    return(0);
}

上記のプログラムをコンパイルして実行する。
% ./io2
適当な数値を入力すると、2 倍した結果が表示される。
3
6

このプログラムをパイプで複数個接続して実行する。
% ./io2 | ./io2 | ./io2 | ./io2 
この例では適当な数値を入力すると、16 倍した結果が表示される。
3
48


7.9   ジョブコントロール (p.125)

  シェルでは複数のプログラムを並列に実行したり、 一部のプログラムの実行を中断して後から再開することができる。 その場合の個々のプログラムの実行状態を制御することをジョブコントロールという。

  実行されるプログラムやコマンドを表す概念として「プロセス」と「ジョブ」がある。 プロセスとは OS が管理、認識する実行の単位で、 一般的なプログラムやコマンドは 1 プロセスとなる。

  それに対してジョブとはシェルが管理、認識する実行の単位で、 単一のプロセスまたは複数のプロセスをパイプで接続したものとなる。

例
% cat file

は 1 プロセスかつ 1 個のジョブであり、

% cat file | sort | uniq | wc -l

は 4 プロセスから構成される 1 個のジョブとなる。
  複数のジョブを並列に実行する場合、 foreground と background の 2 種類の状態がある。 foreground は、ある時点で端末からの入力を受け取るただ一つのジョブとなる。 background は端末からの入力から切り離されており、複数のジョブがこの状態で実行できる。 端末への出力は foreground, background どちらでも可能である。 端末からの入力が必要なジョブを background で実行すると、自動的に以下に示す中断状態になる。

  シェルではジョブに対して様々な操作ができるが、 ジョブコントロールに関連したコマンドには以下のものがある。

例
エディタ emacs または vi を起動する。
% emacs
エディタ実行中に Ctrl-z を入力すると、
実行を「中断」してシェルのプロンプトに戻る。
ここでジョブの一覧を表示すると、
% jobs
[1]  + 中断                emacs
のように中断しているジョブがあることを示す。
エディタは終了しておらず編集内容を保っているので、
次のように実行を再開できる。
% fg %1

再び Ctrl-z でエディタを中断して、別のコマンド top を実行する。
% top
top も Ctrl-z で中断してジョブの一覧を表示すると、
% jobs
[1]  - 中断                emacs
[2]  + 中断(シグナル)      top
のように中断しているジョブが二つあることを示す。

top を foreground に戻して終了する。
% fg %2
次にエディタを background で実行して jobs で確認すると、
% bg %1
[1]    emacs &
% jobs
[1]  + 中断(tty出力)       emacs
端末からの入力を必要とするので自動的に中断される。
foreground に戻して終了する。
% fg %1
  端末からの入力を必要としないジョブは複数個 background で実行できる。 また起動時に background での実行を指定することもできる。

例
// gcc -o fgbg fgbg.c

#include	<stdio.h>
#include	<unistd.h>

int	main(void)
{
    int		i;

    for (i = 0; i < 10; i++) {
	printf("Loop count %d. \n", i + 1);
	sleep(3);
    }
    return(0);
}

上記のプログラムをコンパイルして実行する。
% ./fgbg
終了する前に Ctrl-z で中断して background で実行する。
その後同じプログラムを新たに実行する。
起動時に background での実行を指定する時は & を付ける。
% ./fgbg &
表示されるメッセージから同時に実行していることがわかる。
  ジョブはセミコロン ; で区切って、1 行に複数指定することができる。 その場合最初のジョブの実行が終了したら次のジョブに移る。 ジョブを括弧 (, ) で囲むと、 そのジョブを実行するための専用のシェルが起動されジョブが実行される。 この機能をサブシェルと呼ぶ。

例
% ./fgbg ; ./fgbg 
とすると 2 個のジョブを左から順番に実行する。
ただし先のジョブを background に指定すると同時に実行される。
% ./fgbg & ; ./fgbg
カッコで囲むと専用のシェルが起動されそのシェルにより実行される。
% (./fgbg) ; ./fgbg


7.10   練習問題

  1. コマンドラインの編集機能を試してみなさい。シェル変数 correct や autocorrect を設定した時の自動補完や修正の機能を試してみなさい。

  2. ファイル名の置換に関して、次に示すファイルを指定する表現を考えなさい。拡張子とは、 ファイル名の最後にピリオドに続けて指定するファイルの種類を示す文字列とする。
    1. 拡張子が txt のファイルすべて

    2. アルファベットの大文字で始まる名前のファイルすべて

    3. 5 文字のファイル名を持つファイルすべて

    4. 名前のどこかに abc を含むファイルすべて

    5. 名前の先頭が a で最後が b のファイルすべて

    6. 名前の先頭が a で最後が b の5 文字のファイル名を持つファイルすべて

    7. 名前のどこかに数字を含むファイルすべて

    8. 名前の先頭が a で拡張子が jpg のファイルすべて

    9. 名前の先頭が a で最後が jpg のファイルすべて

    10. 何らかの拡張子を名前に含むファイルすべて

  3. よく使うコマンドについて、自分で新しいエイリアスを登録してみなさい。 そのエイリアスでコマンドが実行できるのを確認した後、 エイリアスの設定を削除してみなさい。

  4. 以下のシェル変数の値がどのように設定されているか調べなさい。 cwd, gid, group, home, host, os, path, shell, term, uid, user

  5. シェル変数 abc に適当な値を設定しなさい。 次に変数 abc と値が設定されていることを確認しなさい。 次に変数 abc の定義を削除しなさい、そして変数 abc と値が削除されたことを確認しなさい。

  6. 以下の環境変数の値がどのように設定されているか調べなさい。 EDITOR, GROUP, HOME, HOST, HOSTNAME, HOSTTYPE, LANG, LOGNAME, MACHTYPE, OSTYPE, PATH, PWD, SHELL, TERM, USER, VENDOR

  7. 環境変数 ABC に適当な値を設定しなさい。 次に変数 ABC と値が設定されていることを確認しなさい。 次に変数 ABC の定義を削除しなさい、そして変数 ABC と値が削除されたことを確認しなさい。

  8. .cshrc または .tcshrc および .login の内容を調べなさい。

  9. コマンド sort にファイル smalldata.txt を入力する方法を 3 種類示しなさい。

  10. 次に示す処理を実現するコマンドの組み合わせをリダイレクトやパイプを用いて示しなさい。
    1. ファイル data.txt の 1 列目の数値だけを取り出す。

    2. 1. の結果から文字 0 を含む行だけを取り出す。

    3. 2. の結果を値の小さい順に並べ換える。

    4. 3. の結果から重複する行を削除する。

    5. 4. の結果をファイル result.txt に書き込む。

    6. 4. の結果が何行あるか調べる。

    7. 4. の結果の先頭部分を表示する。

  11. エディタとコマンド top を起動して、 foreground と background で交互に切替えて実行してみなさい。

  12. 複数のコマンドをセミコロンで区切って実行して、実行の様子を確認しなさい。

  13. 次の 2 種類のコマンド列を実行した時の結果の違いを確認しなさい。 またそのような結果になる理由を説明しなさい。
    % cd ; cd /usr/bin ; pwd ; pwd
    % cd ; (cd /usr/bin ; pwd) ; pwd





8   パターン処理言語 awk (第 10, 11 週)


8.1   awk の概要、実行方法

  パターン処理言語 awk (オーク, オウクと読む) は、 処理対象のテキストデータを 1 行ずつ読み込み、 指定した条件(パターンという)を満たす行に対して指定した処理(アクションという)を施す。 awk のプログラムはパターンとアクションの組を必要に応じて並べることで記述する。 プログラムの一般形は次のようになる。アクションは中括弧で囲む。

パターン { アクション }
  awk のプログラムの記述は C 言語が参考にされており、 多くの場合で C 言語と同じ書き方ができるようになっている。

  パターンとアクションはそれぞれ省略可能で、 パターンを省略するとすべてのレコードにアクションを施し、 アクションを省略するとパターンに一致したレコードを出力する。

  awk では入力データの 1 行を「レコード」と呼び、 レコード内で区切り文字 (空白文字またはTAB) で分割される各単語を「フィールド」と呼ぶ。

  awk の実行の仕方の例を次に示す。 awk のプログラムはコマンドラインから直接記述する方法と、 あらかじめファイルに作成しておいて実行時に指定する方法がある。 入力データのファイルを指定すればそこから、 指定しなければ標準入力から読み込む。

データファイルが以下のようになっているとする。
% head datafile
17767 9158 39017 18547 56401 23807 37962 22764 7977 31949 
22714 55211 16882 7931 43491 57670 124 25282 2132 10232 
8987 59880 52711 17293 3958 9562 63790 29283 49715 55199 
50377 1946 64358 23858 20493 55223 47665 58456 12451 55642 
24869 35165 45317 41751 43096 23273 33886 43220 48555 36018 
53453 57542 30363 40628 9300 34321 50190 7554 63604 34369 
62753 48445 36316 61575 6768 56809 51262 54433 49729 63713 
44540 9063 33342 24321 50814 10903 47594 19164 54123 30614 
55183 42040 22620 20010 17132 31920 54331 1787 39474 52399 
36156 36692 35308 6936 32731 42076 63746 18458 30974 47939 

以下の内容で programfile を用意しておく。このプログラムではパターンは
省略されており、1, 2 番目のフィールドを出力するアクションが指定されている。
% vi (または emacs) programfile
% cat programfile
{print $1,$2}

以下のように 4 種類の方法で実行できる。結果はすべて同じになる。
% awk '{print $1,$2}' datafile
% awk -f programfile datafile
% cat datafile | awk '{print $1,$2}'
% cat datafile | awk -f programfile


8.2   awk のプログラム : 変数

  awk では一般のプログラミング言語と同様に変数を使用できる。 ユーザが定義する通常の変数は宣言をする必要がなく、 プログラム中で必要になった時にいきなり使うことができる。

  awk の変数は整数や浮動小数点数、文字列などの「型」がなく、 同じ変数に数値や文字列をそのまま代入できる。 プログラム中では数値演算をする時には数として解釈され、 文字列に関する処理をする時には文字列として解釈される。 場合によっては誤動作の原因となるので注意が必要である。 対策として、数値用、文字列用の変数を完全に分けて使用することが考えられる。

例
以下は変数に数値、文字列を代入する例である。
数値の場合
% awk '{num=123; print num}' data
文字列の場合
% awk '{num="123"; print num}' data
ダブルクォート(")で囲むと文字列になる。

以下はフィールド変数を数値、文字列として比較する例である。
数値の場合
% awk '$1==123{print $1}' data
文字列の場合
% awk '$1=="123"{print $1}' data
% awk '$1 ~ /^123$/{print $1}' data
  既定義変数としてあらかじめ名前と用途が予約されている「組み込み変数」がいくつかある。 また各フィールドを参照するための「フィールド変数」がある。 使用する機会が多い既定義変数は以下のものである。

  配列を使用することもできる。C 言語の配列と同様に a[5] のように表現する。

例
% awk '{for(i=1;i<=NF;i++){a[i]=$i; print a[i];}}' data


8.3   awk のプログラム : パターンの記述

  パターンには以下の条件が指定できる。

  BEGIN と END は特別なパターンで、 BEGIN は最初のレコードを読み込む前に行なう処理、 END は最後のレコードを処理した後の処理を指定するためにある。 例えば以下のプログラムでは BEGIN で変数の初期化、END で結果の出力を行なう。

例
% awk 'BEGIN{sum=0} {sum+=$1} END{print sum}' data
  正規表現とは特定の文字列を指定する条件の記述法(後述)である。

  式は算術演算や論理演算を組み合わせて表現される。 また正規表現やアクションで用いる文字列関数を含めることができる。 式の表現では以下の演算子が使用できる。一部を除いて C 言語と同じ表現が使用できる。

例
% awk '$1==10 {print}' data
% awk '$1*$2<=10 {print}' data
% awk '$1 ~ /^123$/ {print}' data
  正規表現や式は単独で指定する他に、複数を組み合わせて指定することもできる。 評価の優先順位がわかり難い場合は必要に応じて括弧を加える。

例
% awk '($1==10) && ($2!=20) {print}' data
% awk '($1 ~ /^123$/) || ($2<20) {print}' data
% awk '!($1 ~ /^123$/) {print}' data

二つのパターン p1, p2 をカンマで区切って並べると、
p1 にマッチしてから p2 にマッチするまでという条件で範囲を指定できる。
% awk 'NR==3, NR==10 {print $1}' data


8.4   正規表現

  正規表現とは特定の文字列を指定する条件の記述法で、 表現法は異なるがシェルと操作方法で取り上げたファイル名の置換機能と似ている。 正規表現はこの機能をより一般化して強化したものといえる。

  awk における正規表現は前後をスラッシュで囲んで表現する。

  以下に示す特定の文字(メタ文字)は本来のその文字として解釈されず、 文字の繰り返しや位置などを表す特別な意味を持つ。 メタ文字は \ . ^ $ [ ] | + - * ? ( ) { } である。 / はメタ文字ではないが、正規表現の最初と最後を表すので、 通常の文字として扱いたい場合は注意が必要である。

  各メタ文字の機能、正規表現の記述を以下に示す。

例
レコード中に abc を含む。(場合にマッチしてそのレコードを出力する)
% awk '/abc/ {print}' data

レコード中に . を含む。(\ でメタ文字の機能を無効にしている)
% awk '/\./ {print}' data

レコード中に任意の 1 文字を含む。
% awk '/./ {print}' data

レコードの先頭が abc である。
% awk '/^abc/ {print}' data

レコードの最後が abc である。
% awk '/abc$/ {print}' data

レコードが abc である。(^,$ が両方あるので abc 以外の文字を含むことができない)
% awk '/^abc$/ {print}' data

レコードの先頭が a,b,c のどれかである。
% awk '/^[abc]/ {print}' data

レコードの先頭が abd, acd のどちらかである。
% awk '/^a(b|c)d/ {print}' data

レコードの先頭が abbb...bd, accc...cd, acbbd, abcbd などのどれかである。
% awk '/^a(b|c)+d/ {print}' data
  ここまでの例ではマッチングの対象がレコード全体であったが、 次の演算子を使うことでマッチングの対象を単独のフィールド変数または変数に限定できる。

パターンの指定で

フィールド変数 ~ /正規表現/
変数 ~ /正規表現/

とすることで対象をフィールド変数、変数に限定する。

フィールド変数 !~ /正規表現/
変数 !~ /正規表現/

とすることで対象にマッチしないという条件も指定できる。
例
フィールド変数 1 に abc を含む。(場合にマッチしてそのレコードを出力する)
% awk '$1 ~ /abc/ {print}' data

変数 var に任意の 1 文字を含む。
% awk 'var ~ /./ {print}' data

フィールド変数 1 の先頭が abc でない。
% awk '$1 !~ /^abc/ {print}' data

変数 var の最後が abc でない。
% awk 'var !~ /abc$/ {print}' data

フィールド変数 1 が abc である。(^,$ が両方あるので他の文字を含むことができない)
% awk '$1 ~ /^abc$/ {print}' data


8.5   awk のプログラム : アクションの記述

  アクションには以下の内容が指定できる。 パターンと同様に式や制御構文に正規表現を含むこともできる。

  式、出力文の printf、制御構文は C 言語とほぼ同じ記述ができる。 複数の処理を指定したい場合は、セミコロン ; で区切って並べることができる。

  式はパターンと同様の内容が記述できる。

  出力文 print, printf の違いは、出力時のフォーマットを指定するかどうかで、 print は変数や数値を(フォーマット指定なしで)簡単に出力したい場合に使用する。 printf は桁数やフォーマットなどを指定して出力を整形したい時に使用する。 printf では C 言語と同様に %c, %s, %4d, %0.3f, %04x のような指定ができる。

例
% awk '{print $1,$2}' data
% awk '{printf("%d   %4d\n",$1,$2);}' data
  制御構文は以下のものが使用できる。記述の仕方はいずれも C 言語の場合と同じである。

例
% awk '{for (i=1;i<=NF;i++) sum+=$i; print sum;}' data
% awk '{if (0==NF%2) printf("even\n"); else printf("odd\n");}' data
% awk '{while ($1<10) {print $1; $1++;}}' data
  文字列関数はいくつかあるが、ここでは代表的なものを 2 個だけ紹介する。

例
% awk '10<length($1) {print $1}' data
% awk '{n=length($1); s=substr($1,3); print n, s}' data


8.6   サンプルプログラム

  以下に簡単な awk のプログラムをいくつか示す。

各レコード(行)の 1 番目のフィールドを出力する
% awk '{print $1}' data

各レコードの 1,2 番目のフィールドを入れ換えて出力する
% awk '{print $2,$1}' data

10 行目(10 番目のレコード)を出力する
% awk 'NR==10{print $0}' data
% awk 'NR==10{print}' data
% awk 'NR==10' data

1 番目のフィールドの値が 10 でなければ、そのレコードを出力する
% awk '10!=$1{print $0}' data
% awk '10!=$1{print}' data
% awk '10!=$1' data

各レコード中のフィールドの和を求める
% awk '{sum=0; for (i=1;i<=NF;i++) sum+=$i; print sum}' data

1 番目のフィールドの和を求める
% awk 'BEGIN{sum=0} {sum+=$1} END{print sum}' data

行の総数(レコードの総数)を求める
% awk 'END{print NR}' data

フィールドの数が奇数か偶数かで異なるメッセージを出力する
% awk '{if (0==NF%2) printf("even\n"); else printf("odd\n");}' data

1 番目のフィールドの平均値を求める
% awk 'BEGIN{sum=0} {sum+=$1} END{print sum/NR}' data
(この例はこれまで最後の部分が誤って sum/NF となっていましたが、
 2007/01/09 に正しい内容に修正した。)

文字列 "abc" を含むレコードを出力する
% awk '/abc/{print $0}' data
% awk '/abc/{print}' data
% awk '/abc/' data

各行に行番号を付ける、レコードに通し番号を付ける
% awk '{print NR,$0}' data

各行に 4 桁ずつの行番号を付ける、レコードに通し番号を付ける
% awk '{printf("%04d: %s\n",NR,$0);}' data

アルファベットだけから構成される単語を取り出して表示する
awk '{for (i=1;i<=NF;i++) if ($i ~ /^[A-Za-z]+$/) print $i;}' data


8.7   練習問題

  1. awk における出力で、print $1,$2 と print $1 $2 の違いを確認して説明しなさい。

  2. % awk 'NR==10{print $0}' data と
    % awk 'NR==10{print}' data と
    % awk 'NR==10' data の結果が同じになる理由を説明しなさい。

  3. % awk 'NR==1, NR==5 {print}' data と
    % awk 'NR==5, NR==1 {print}' data の違いを確認して説明しなさい。

  4. awk の正規表現に関して、レコード、フィールドを次に示す条件で選択する awk のプログラムの表現を考えなさい。
    1. 最初(1 番目)のフィールドが abc である

    2. 最初のフィールドの先頭が .txt にマッチ

    3. 最初のフィールドの先頭が .txt でない

    4. 最初のフィールドの最後が .txt にマッチ

    5. 最初のフィールドが 5 文字である

    6. 最初のフィールドの先頭が a で最後が b で 5 文字からなる

    7. レコードのどこかに数字を含む

    8. レコードのどこかに abc または cba を含む

    9. レコードの先頭がアルファベットの大文字で始まる

    10. レコードの先頭が a で最後が b である

    11. レコードの先頭が a でどこかに jpg を含む

    12. レコードの先頭が a で最後が jpg である

    13. レコードに括弧 ( または ) を含まない

    14. レコードに abc を 2 個以上含む

    15. レコードに abc を連続して 2 個以上含む

  5. 3 次元の座標データが data3d.txt に記録されている。 data3d.txt に対して以下の処理を awk で実行しなさい。
    1. 何行あるか求める

    2. "1234" という表現を含む行を表示する

    3. 1 次元目のデータで 100 未満のデータの個数を求める

    4. 2 次元目のデータの最大値、最小値を求める

    5. 3 次元目のデータの平均値を求める

    6. 3 次元目のデータで平均値より大きなデータの個数を求める

  6. コマンド ps の出力が ps.txt に記録されている。 ps.txt に対して以下の処理を awk で実行しなさい。
    1. 第 1 列のユーザ名だけを取り出す

    2. root が所有するプロセスの一覧と総数を求める

    3. 8 月 28 日に起動されたプロセスの一覧と総数を求める

    4. /usr/sbin にあるプログラムで起動されているものの一覧と総数を求める

  7. awk のオンラインマニュアルの一部が awk.txt に記録されている。 awk.txt に対して以下の処理を awk で実行しなさい。
    1. "the" という文字列を含む行を表示する

    2. 先頭が大文字で残りが小文字で表記されている単語を抽出して表示する

    3. 末尾にピリオドが付いている単語を抽出して表示する

    4. 最も長い単語を調べて表示する (ハイフン - で連結された単語は 1 語とする)

    5. アルファベットだけから構成される最も長い単語を調べて表示する





9   シェルスクリプト、作業の自動化 (第 12, 13 週)


9.1   シェルスクリプトとは

  シェルスクリプトとは、通常シェルを対話的に使用して実行しているコマンドなどを、 プログラムのような形でファイルに記録しておき、 必要な時に呼び出して実行するための仕組みである。 シェルスクリプトは様々な制御構文を持つインタプリタ言語であり、 登録したコマンドを順番に実行するだけではなく、条件判断や繰り返し、 変数によるデータの記憶も可能となっている。

  シェルスクリプトではこれまでに取り上げた様々な内容 (5 章 データを記録、参照する仕組み、 6 章 コマンド、7 章 シェルによる操作環境、8 章 パターン処理言語 awk) をシェルスクリプトの内部から利用することが可能である。そのため、 コマンドや awk などのプログラミング言語で実現した方が簡単な処理はそれらを用いて実現し、 ファイル操作はシェルが備えている強力な機能を利用して実現し、 それ以外の制御構造をシェルスクリプトのインタプリタ言語で記述するといった感じで、 それぞれの便利/強力な機能をうまく組み合わせることで、 ある程度複雑な処理でも簡潔に表現、記述することができる。

  シェルにはいくつかの種類があり、シェルスクリプトが備える機能もそれぞれ異なるが、 慣例としてシェルスクリプトは sh (bsh, Bourne shell と表現することもある) が備える インタプリタ言語の文法で記述し、sh で実行することが多い。 この章でも sh のインタプリタ言語の文法を取り上げ、解説や例も sh に合わせて記述する。 なおここではシェルスクリプトのすべての機能は取り上げられないので、 主要な機能に絞って説明する。

  以下では簡単な例として、同一の処理をシェルから対話的に実行する場合と、 シェルスクリプトとして記述してから実行する場合の手順を示す。

処理の内容は、/bin に置かれているコマンドの中から、サイズが 
100 byte 未満のものだけを取り出して表示する。

対話的に実行する場合は次のように書ける。

% ls -l /bin | awk '$5<100{print}'

シェルスクリプトとして実行する場合は、まずエディタを使って
ファイルに実行する内容を書く。ファイル名は仮に sample.sh 
とする。
% vi (または emacs) sample.sh
#!/bin/sh

ls -l /bin | awk '$5<100{print}'

ファイルに実行権を付加する。
% chmod 700 sample.sh
または
% chmod u+x sample.sh

これで実行できる。
% sample.sh
  この例だけを見ると、シェルスクリプトは非常に手間がかかるように見えるが、 何回も実行する場合はシェルスクリプトの方が楽になる。 対話的に実行する場合は毎回必ず次のように書く必要がある。

% ls -l /bin | awk '$5<100{print}'
これに対して、シェルスクリプトは一旦作成してしまえば名前の
指定だけで実行できる。
% sample.sh
  また数行に渡るような複雑な処理を、対話的に記述して実行するのは難しいので、 その場合もシェルスクリプトの仕組みを利用することが多い。



9.2   変数、パラメータ

  シェルスクリプト内で値を覚えておく仕組みがパラメータで、 名前の付いているパラメータが変数となる。 シェルスクリプトで使用する変数は、整数や文字などの型はなく、事前の宣言も必要ない。 必要になった時にいきなり使用することができる。 変数に値を代入する時は'='を使う。制約として、=の前後に空白文字を入れてはいけない。

  変数名には、アルファベット、数字、アンダスコア (_) のみが使える。 ただし、最初の文字に数字は使えない。

  変数の内容を参照する時は変数名の前に $ を付ける。この操作をパラメータの展開と呼ぶ。

  以下の例 sample2.sh では、変数名に $ を付けた場合と付けない場合の出力の違いを示す。 echo は変数や文字列を出力するシェルのコマンドである。

% vi (または emacs) sample2.sh
#!/bin/sh

abc=def
echo abc
echo $abc

% chmod 700 sample2.sh
% sample2.sh
  ユーザが定義する変数の他に、 シェル内部であらかじめ内容や機能が決められているパラメータがある。 以下に代表的なパラメータを示す。$*, $0, $1, $2 は位置パラメータと呼ぶ。

$#	シェルスクリプト起動時に指定されたコマンドライン引数の個数
$*	個々のコマンドライン引数
$0	シェルスクリプトの名前
$1	1 個目のコマンドライン引数
$2	2 個目のコマンドライン引数
.
.
.
  コマンドライン引数とは、 シェルスクリプト動作時に空白文字で区切って同時に指定する文字列のことで、 以下の例の abc や 10 が該当する。 シェルスクリプトではコマンドライン引数を扱うための変数として、 位置パラメータが用意されている。

% sample.sh abc 10
  以下の例 sample3.sh, sample3b.sh では、$#, $0, $1, $* の機能を示す。 コマンドライン引数の個数や内容を表示する。

% vi (または emacs) sample3.sh
#!/bin/sh

echo $#
echo $0
echo $1
echo $2

% chmod 700 sample3.sh
% sample3.sh aaa bbb ccc ddd
  下記の例で使われている for ループの説明は、後に出てくる制御構造の項にあるので、 必要ならそちらを参照する。

% vi (または emacs) sample3b.sh
#!/bin/sh

for str in $*
do
	echo $str
done

% chmod 700 sample3b.sh
% sample3b.sh aaa bbb ccc ddd eee fff ggg hhh
  変数名の範囲を明確に指定するために、必要な場合は変数を中括弧 {, } で囲む。 以下の例 sample4.sh, sample5.sh では、 中括弧 {, } を付けた場合と付けない場合の出力結果の違いを見ることができる。

% vi (または emacs) sample4.sh
#!/bin/sh

abc=111
abcd=222
echo $abcd
echo ${abc}d

% chmod 700 sample4.sh
% sample4.sh
% vi (または emacs) sample5.sh
#!/bin/sh

echo $10
echo ${10}

% chmod 700 sample5.sh
% sample5.sh 111 222 333 444 555 666 777 888 999 aaa


9.3   コマンド置換

  シェルスクリプト内でコマンドを実行する場合に、次のように指定することで、 コマンドを書いた位置でコマンドの実行結果を置き換えることができる。 実行結果で置き換えたいコマンドをバッククォート (`) で囲む。 この機能を使うことで、コマンドの結果を一時ファイルに記録することなく、 次の処理で直ちに利用することができる。

  以下の例 sample6.sh では、通常のコマンド date の出力を変数 abc に代入して、 その後利用する例となっている。 コマンド date を端末エミュレータから単独で実行して、結果を先に見ておいてもよい。

% vi (または emacs) sample6.sh
#!/bin/sh

abc=`date`
echo $abc
echo $abc | awk '{print $4}'

% chmod 700 sample6.sh
% sample6.sh


9.4   引用、クォート

  引用とは特殊な意味を持つ文字や単語 (演算子、空白、キーワードなど) の意味を打ち消すために用いる指定である。 引用には、シングルクォート文字のペアを使う方法、 ダブルクォート文字のペアを使う方法、 バックスラッシュ文字を使う方法の 3 種類がある。

○ シングルクォート文字

シングルクォート (') のペアで囲まれた文字は、すべてその文字その
ままとして扱われる。ただしシングルクォートだけは別で、
シングルクォートで囲った文字列の中にシングルクォートを含めること
はできないという制約がある。

○ ダブルクォート文字

ダブルクォート (") のペアで囲まれた文字は、ドル記号文字 ($) 、バック
クォート文字 (`) 、バックスラッシュ文字 (\) を除き、すべてその文字
そのままとして扱われる。

○ バックスラッシュ

バックスラッシュ (\) は、その後ろの 1 文字を、文字そのままとして
扱うように指示する。
  以下の例 sample7.sh では、クォート無し、シングルクォート、 ダブルクォートの 3 種類で出力がどう変化するか比較することができる。

% vi (または emacs) sample7.sh
#!/bin/sh

abc=`date`

echo $*
echo `date`
echo $abc

echo '$*'
echo '`date`'
echo '$abc'

echo "$*"
echo "`date`"
echo "$abc"

echo '$*'
echo "$*"
echo '"$*"'
echo "'$*'"

% chmod 700 sample7.sh
% sample7.sh aaa bbb ccc


9.5   制御構造


9.5.1   if

  シェルスクリプトの if は指定した条件を満たした時に処理を行なう。 C 言語の if とほぼ同じ機能を持つが、記述の仕方が一部異なるので注意する。

  以下の例 sample8.sh では、起動時に指定するコマンドライン引数の個数の違い (2 個未満、3 個未満、3 個以上)を if 文で判定して、出力するメッセージを変化させている。

% vi (または emacs) sample8.sh
#!/bin/sh

if [ $# -lt 2 ]
then
	echo 111
elif [ $# -lt 3 ]
then
	echo 222
else
	echo 333
fi

% chmod 700 sample8.sh
% sample8.sh aaa 
% sample8.sh aaa bbb 
% sample8.sh aaa bbb ccc
  $# はシェルスクリプト起動時に指定したコマンドライン引数の個数である。 elif は else if の意味を表す。最後は fi で閉じる。 角括弧 [, ] で囲まれた部分が条件を表す。 [ を使う場合は後ろの ] は省略できない。 -lt は数として比較する時の < を表す。

  if の条件の部分は角括弧 [, ] で囲まれているが、 [ はもともと test というコマンドであり [ はその別名である。 よって条件の部分は 2 種類の書き方があり、全く同じ動作をする。 以下にその例を示す。 sample8b.sh ではコマンドライン引数の個数を判定してメッセージを表示する。

% vi (または emacs) sample8b.sh
#!/bin/sh

if [ $# -eq 0 ]
then
	echo no option 1
else
	echo some options 1
fi

if test $# -eq 0
then
	echo no option 2
else
	echo some options 2
fi

% chmod 700 sample8b.sh
% sample8b.sh
% sample8b.sh aaa bbb
  以下に指定できる条件の代表的なものを示す。 file はファイル名、str は文字列、int は整数、exp は式を表し、 それぞれ定数または変数を指定できる。

-d file		file がディレクトリである
-f file		file が通常のファイルである
-r file		file がプロセスで読み出し可能である
-w file		file がプロセスで書き込み可能である
-x file		file がプロセスで実行可能である
-s file		file のサイズが 0 でない
-------------------------------------------------------
str		str が空でない
-n str		str が空でない
-z str		str が空である
str = str2	str と str2 が等しい
str != str2	str と str2 が等しくない
-------------------------------------------------------
int -eq int2	int と int2 が等しい
int -ne int2	int と int2 が等しくない
int -ge int2	int >= int2
int -gt int2	int > int2
int -le int2	int <= int2
int -lt int2	int < int2
-------------------------------------------------------
exp		exp が真である
! exp		exp が偽である
exp -a exp2	exp と exp2 の論理積, AND
exp -o exp2	exp と exp2 の論理和, OR
  以下で条件の書き方の実例を示す。 sample8c.sh ではファイルの様々な属性を調べて表示する。 /etc/aliases は /etc にある設定ファイルの一つである。

% vi (または emacs) sample8c.sh
#!/bin/sh

if [ -d $1 ]
then
	echo $1 is a directory
fi

if [ -f $1 ]
then
	echo $1 is a file
fi

if [ -r $1 ]
then
	echo $1 is readable
fi

if [ -w $1 ]
then
	echo $1 is writable
fi

% chmod 700 sample8c.sh
% sample8c.sh /etc/aliases
  次の例 sample8d.sh では文字列の比較をする。 $1 が空文字列か判定する、その後 $1 が存在する場合は aaa と一致するか判定する。

% vi (または emacs) sample8d.sh
#!/bin/sh

if [ -z $1 ]
then
        echo '$1' is empty
fi

if [ $# -ge 1 ]
then
    if [ $1 = aaa ]
    then
        echo '$1' is aaa
    fi
fi

% chmod 700 sample8d.sh
% sample8d.sh
% sample8d.sh aaa
% sample8d.sh bbb
  次の例 sample8e.sh では数値の比較をする。

% vi (または emacs) sample8e.sh
#!/bin/sh

if [ $1 -eq 5 ]
then
        echo $1 is $num
fi

num=5

if [ $1 -ne $num ]
then
        echo $1 is not $num
fi

if [ $1 -gt $num ]
then
	echo $1 is greater than $num
fi

if [ $1 -lt $num ]
then
	echo $1 is later than $num
fi

% chmod 700 sample8e.sh
% sample8e.sh 3
% sample8e.sh 5
% sample8e.sh 7
  次の例 sample8f.sh では複数の条件を論理演算で結合する。

% vi (または emacs) sample8f.sh
#!/bin/sh

num=5

if [ $1 -ne $num ]
then
        echo $1 is not $num
fi

if [ ! $1 -ne $num ]
then
        echo $1 is not not $num
fi

if [ $1 -eq 3 -a $2 -eq 5 ]
then
	echo $1 is 3 and $2 is 5
fi

if [ $1 -eq 3 -o $2 -eq 5 ]
then
	echo $1 is 3 or $2 is 5
fi

% chmod 700 sample8f.sh
% sample8f.sh 3 3
% sample8f.sh 5 5
% sample8f.sh 3 5
% sample8f.sh 7 5


9.5.2   for

  シェルスクリプトの for ループは指定した回数の繰り返しではなく、 変数に指定した文字列のリストから順に 1 個ずつ値を代入して、 各値に対して処理を行なう。 一連のファイルに対して同じ処理を繰り返したい時に便利に使える。

  以下の例 sample9.sh では、曜日を表す文字列をリストとして for 文に指定して、 順に 1 個ずつ取り出し出力する。

% vi (または emacs) sample9.sh
#!/bin/sh

for day in Sunday Monday Tuesday Wednesday Thursday Friday Saturday
do
	echo $day
done

% chmod 700 sample9.sh
% sample9.sh
  以下の例 sample10.sh では、/etc にある a から始まるファイル名のファイルをすべて指定して、 順に 1 個ずつ取り出して if 文によりファイルかファイル以外か判定した後にメッセージを出力する。 /etc/a* は 7.2 ファイル名の置換、字句解析で取り上げた機能を利用している。 このように for ループを用いると、あるディレクトリにある、 特定の名前にマッチするファイルだけを取り出して操作することができる。

% vi (または emacs) sample10.sh
#!/bin/sh

for file in /etc/a*
do
	echo -n $file, " "
	if [ -f $file ]
	then
		echo normal file
	else
		echo directory or something
	fi
done

% chmod 700 sample10.sh
% sample10.sh


9.5.3   while

  シェルスクリプトの while は指定した条件を満たす間処理を繰り返す。 C 言語の while とほぼ同じ機能を持つ。

  以下の例 sample11.sh では、シェルスクリプト内で整数をカウントして 0 から 9 まで表示する。expr は数の計算を行なうコマンドである。 一定回数だけ処理を繰り返したい場合はこのように記述できる。

% vi (または emacs) sample11.sh
#!/bin/sh

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

% chmod 700 sample11.sh
% sample11.sh


9.5.4   break

  break は while または for ループの繰り返しを終了する。 C 言語の break とほぼ同じ機能を持つ。

  以下の例 sample12.sh では、 コマンドライン引数に skip が現れたらそれ以後の表示をしないという動作をする。

% vi (または emacs) sample12.sh
#!/bin/sh

for str in $*
do
	if [ $str = skip ]
	then
		break
	fi
	echo $str
done

% chmod 700 sample12.sh
% sample12.sh aaa bbb ccc ddd skip eee fff


9.5.5   continue

  continue は while または for ループの次の繰り返しに制御を移す。 C 言語の continue とほぼ同じ機能を持つ。

  以下の例 sample13.sh では、 コマンドライン引数に skip が現れたらその場合だけ表示をしないという動作をする。 上記 sample12.sh の動作と比較すると両者の違いがわかる。

% vi (または emacs) sample13.sh
#!/bin/sh

for str in $*
do
	if [ $str = skip ]
	then
		continue
	fi
	echo $str
done

% chmod 700 sample13.sh
% sample13.sh aaa bbb ccc ddd skip eee fff



9.6   ファイル名の操作

  ここで取り上げるファイル名を操作するコマンド basename と dirname は、 シェルスクリプト自体が備える機能ではないが、 シェルスクリプトでファイル名を操作する場合によく使われ大変便利なものなので合わせて説明する。

  コマンド basename はディレクトリを含んだファイル名から、 ディレクトリ部分を取り除いた名前を返す。 またファイル名から取り除きたい文字列を指定した場合は、 ファイル名から指定した文字列を取り除いた名前を返す。

  コマンド dirname はディレクトリを含んだファイル名から、 ファイル名を取り除いた名前を返す。

  以下の例 sample14.sh では、指定したディレクトリ /etc にある a から始まるファイルに対して、 basename と dirname がどのように働くか見ることができる。 basename を使うとファイル名だけ取り出せ、拡張子を取り除くこともできる。 逆に dirname を使うとディレクトリを表す部分だけ取り出すことができる。

% vi (または emacs) sample14.sh
#!/bin/sh

for file in /etc/a*
do
	echo $file
	echo `basename $file`
	echo `basename $file .cfg`
	echo `dirname $file`
	echo ------------------------------------
done

% chmod 700 sample14.sh
% sample14.sh


9.7   シェルスクリプトの例

  以下では様々な処理を実現するシェルスクリプトの具体的な例を示す。


9.7.1   大文字の拡張子 JPG を小文字の jpg に変更する

  Windows で作成したファイルは拡張子が大文字になる場合があるが、 拡張子を小文字に変換する。 ディレクトリ内の拡張子が JPG のファイルを一括して変換する。

評価用の仮のファイルを作成する
% touch f001.JPG f002.JPG f003.JPG f004.JPG f005.JPG
% vi (または emacs) sample15.sh
#!/bin/sh

for file in *.JPG
do
	mv $file `basename $file JPG`jpg
done

% chmod 700 sample15.sh
% sample15.sh
% ls


9.7.2   一定の形式のファイル名で通し番号を付けてファイルを作成する

  統一された名前(仮に data とする)に通し番号を付けたファイル名で一連のファイルを作成する。

% vi (または emacs) sample16.sh
#!/bin/sh

num=1
while [ $num -lt 20 ]
do
	num2=`echo $num | awk '{printf("%04d",$1);}'`
	touch data$num2.txt
	num=`expr $num + 1`
done

% chmod 700 sample16.sh
% sample16.sh
% ls


9.7.3   デジタルカメラの画像ファイルの名前を内容がわかるファイル名に変更する

  デジタルカメラで撮影した画像ファイルが非常にたくさんある。 以下の例のように内容がわかるファイル名に変更する。 DCN00001.jpg → ryokou0001.jpg

  事前に作成するファイル名の部分を書き換えた sample16.sh を利用して、 DCN00001.jpg の形式で通し番号のファイルを数十枚作成しておく。

% vi (または emacs) sample17.sh
#!/bin/sh

name=ryokou

for file in *.jpg
do
	num=`basename $file .jpg`
	num2=`echo $num | awk '{printf("%s",substr($1,5));}'`
	mv $file ${name}${num2}.jpg
done

% chmod 700 sample17.sh
% sample17.sh
% ls


9.7.4   ls の結果を日時をファイル名にしたファイルに記録する

% vi (または emacs) sample18.sh
#!/bin/sh

ls -l > `date +%Y%m%d%H%M%S`.ls

% chmod 700 sample18.sh
% sample18.sh


9.7.5   複数のファイルで特定の単語を含む行数の一覧表を作成する

  複数のファイルの各行から指定した単語を含む行を抜き出して行数の数える。 その結果をファイル名と合わせて表示する。

  あらかじめ /usr7/denshi2/naga/DATA から awk.txt, cat.txt, cp.txt, kill.txt, ls.txt, mkdir.txt, mv.txt, ps.txt を自分のディレクトリにコピーしておく。

% vi (または emacs) sample19.sh
#!/bin/sh

if [ $# -lt 1 ]
then
        echo Usage: $0 word
	exit
fi

word=$1

for file in *.txt
do
	echo -n $file
	grep $word $file | wc -l
done

% chmod 700 sample19.sh

検索する単語を仮に"the"とする
% sample19.sh the


9.7.6   学生の出席日数を数える

  毎回の実習に出席した学生が出席確認用のファイルを作成するので、 そのファイルを集計して学生の出席日数を数える。

あらかじめ /usr7/denshi2/naga/DATA からファイル 2006.tar
を自分のディレクトリにコピーしておく。
その後、
% tar xvf 2006.tar 
を実行しておく。
% vi (または emacs) sample20.sh
#!/bin/sh

for dir in 2006/????
do
	cd $dir
	ls ex* > ../`basename $dir`.dat
	cd ../..
done

cat 2006/????.dat | sort | \
awk '{if (last != $1) {last=$1;printf("%d\n%s ",num,$1);num=1;} 
      else num++;}
     END{printf("%d\n",num);
    }' | awk '1<NR' > 2006/result.dat

cat 2006/result.dat

% chmod 700 sample20.sh
% sample20.sh

結果は 2006/result.dat に記録されているので、
一旦答を求めたら次からは 
% less 2006/result.dat 
などでファイルの内容を表示すればよい。



9.8   練習問題

  1. 次の機能を持つシェルスクリプトを記述しなさい。
    1. コマンドライン引数の個数が1個の場合とそうでない場合で、 異なるメッセージを表示する。

    2. コマンド % ps aux の出力から、 所有者が自分になっているプロセスを取り出して表示する。

    3. コマンドライン引数を1個指定したときに、$1=??? と表示する。 ??? には $1 の値が入る。

    4. コマンド date の出力から時間の部分だけ取り出して表示する。

    5. コマンド date の出力から何月何日の部分だけ取り出して表示する。

    6. コマンドライン引数としてファイル名を指定したときに、 ファイルかディレクトリか区別して表示する。

    7. コマンドライン引数としてファイル名を指定したときに、 実行可能かどうか区別して表示する。

  2. 仮想学科 ex の 2007 年度から 2012 年度までの各年度の学生の、 個人情報と期末試験の成績がファイルに記録されている。 これらのデータに対して次の処理を行ない結果を求めなさい。 項目の内容は左から順に、学籍番号、性別、出身県、年齢、身長、体重、 国語、算数、理科、社会、英語の点数である。 データが記録されているファイル ex07.dat ex08.dat ex09.dat ex10.dat ex11.dat ex12.dat は、/usr7/denshi2/naga/DATA から 自分のディレクトリにコピーしなさい。
    1. 人数が一番多い年度はいつか。

    2. 愛知県出身の学生が一番多い年度はいつか。

    3. 女性が一番多い年度はいつか。

    4. 21 歳の学生が一番多い年度はいつか。

    5. 平均身長が一番高い年度はいつか。

    6. 男性の平均身長が一番高い年度はいつか。

    7. 平均体重が一番重い年度はいつか。

    8. 国語の最低点が一番高い年度はいつか。

    9. 算数の平均点が一番低い年度はいつか。

    10. すべての年度を通して最も身長が高い学生は誰か。

    11. すべての年度を通して 5 科目の合計得点が最も高い学生は誰か。

    12. すべての年度を通して平均点が最も高い科目は何か。





10   OS が備える主要な機能


10.1   カーネル



10.2   プロセス、スケジューリング



10.3   メモリ管理、仮想記憶



10.4   ファイルシステム



10.5   システムコール



10.6   ユーザインタフェース



10.7   入出力、割り込み



10.8   通信、ネットワーク



10.9   練習問題