(教材)10【Unixコマンドまとめ(catを中心に)】
はじめに――cat が分かればすべてが分かる!?
Unixの基本的なコマンドのまとめとして,ここではcat コマンドを例にして説明する.cat はUnixの基本コマンドがもつ特徴,すなわちオプションや引数の与え方はもちろん,標準入力,標準出力,リダイレクション,パイプ等をすべて備えているので,「cat が分かればUnix基本コマンドのすべてが分かる」と言っても過言ではない.今まで何度も使ってきたcat だが,どういう機能をもちどういう使い方をするのか,必ずUnix環境にログインして以下の内容を実際に実行しながら,今一度しっかり確かめてほしい.
なお,以下の説明は,計算機実習1におけるUnixの基本を一通り学習していることを前提としている.わからないことに出くわしたら,まず教科書と実習サイトの該当箇所をよく読み直した上で,操作を進めていくこと.
ファイルの準備と確認
まず,cat コマンドを使ってファイル(file1とfile2)を作っておこう.データが入力できたらCtrl+D(コントロールキーを押しながらD)で,cat コマンドの標準入力状態から抜け出す.
code:▼はEnter,■はプロンプト
$ cat > file1▼
aaa▼
This is file No.1.▼
$ cat > file2▼
bbb▼
This is file No.2.▼
$ ■
作成できたらファイルの内容を表示させて確認しておこう.
code:▼はEnter,■はプロンプト
$ cat file1▼
aaa
This is file No.1.
$ cat file2▼
bbb
This is file No.2.
$ ■
ファイルの連結---cat本来の機能
cat 本来の機能はファイルを連結することである.
("cat"は「結びつける」という英単語 concatenate または catenate から来ている)
「連結する」とはどういうことか,次の例で確かめてみよう.
code:▼はEnter,■はプロンプト
$ cat file1 file2▼
aaa
This is file1.
bbb
This is file2.
$ ■
ここで確かめられることを以下に挙げる.
1. 1行目のように,cat は指定された複数のファイルの内容を指定された順に連結し,標準出力に書き出す.
例ではfile1とfile2が引数となる.
2. 標準出力は通常,ディスプレイにつながっているので「標準出力に書き出す」=「ディスプレイに表示される」.
上記の例ではfile1とfile2の内容が(並べた順に)連結されて画面に表示されている.
また,cat で指定するファイルはいくつでも並べることができる.たとえば次のような表記も可能である.
$ cat file1 file2 file1 file2
さらに,ファイルの指定にはワイルドカードを用いることもできる.たとえば次のような表記も可能である.
$ cat file?
$ cat file*
※上の例はそれぞれどのように表示されるか考えてみよう.2つめの例ではどのファイルがどの順序で連結されるかを考慮する必要がある.
(ディレクトリに存在するファイルによって結果が異なる)
ファイルへの出力――リダイレクション">"を使う
cat で連結したファイルの内容をディスプレイにではなく,ファイルに出力することもできる.
code:▼はEnter,■はプロンプト
$ cat file1 file2 > file3▼
$ cat file3▼
aaa
This is file1.
bbb
This is file2.
$ ■
この例では書き出す先を標準出力(ディスプレイ)からファイルに切り替えている.具体的にはfile1とfile2の内容を連結し,file3というファイルに出力している.
このように標準出力から他の出力先 (ほとんどがファイル) に切り替えることをリダイレクションといい,リダイレクション記号として「>」が用いられる.
※上の例で,file3が存在しなければ新規に作成される.では最初からfile3が存在しているとしたらどうなるか,考えてみよう.
ファイル内容の表示――1つだけファイル指定
cat の引数で指定するファイルの数が1つの場合,連結するファイルがないので,ファイル内容が標準出力にそのまま出力される.また,ファイル内容の表示とリダイレクションを組み合わせることで,ファイルのコピーが行える.次の例を確認してみよう.
code:▼はEnter,■はプロンプト
$ cat file1▼
aaa
This is file1.
$ cat file1 > file4▼
$ cat file4▼
aaa
This is file1.
$ ■
この例では,file1の内容がfile4にコピーされている.ファイルのコピーには通常,cp コマンドを使うが,内部では同じことをやっていると考えてよい.
ファイルの作成――ファイル指定なしの場合
catの引数としてファイルが1つも指定されない場合,標準入力からの読み込み状態になる.標準入力は通常キーボードにつながっている.つまり「標準入力から読み込む」=「キーボードから入力する」.
リダイレクションを使えば,catを使ってキーボードから入力した内容をファイルにすることができる.
code:▼はEnter,■はプロンプト
$ cat > file5▼
abcde▼
This is file5.▼
[Ctrl+D]
$ ■
cat の直後がファイル名ではなくリダイレクション記号「>」であることに注意しよう.リダイレクション記号の後のfile5は出力先ファイルであり,標準出力 (ディスプレイ) からファイルに切り替えたことを示している.その結果,標準入力 (キーボード) から文字列を入力し,Ctrl+Dで入力状態を終了し,出力先としてファイルfile5に書き込んでいる.
※これが第2回で学んだ,エディタを使わずにファイルを作る方法である.また,このドキュメントの最初で,ファイルfile1,file2を作成したのとまったく同じ方法である.
ファイルからの入力――リダイレクション"<"を使う
読み込み元を標準入力 (キーボード) からファイルに切り替え,ファイルの内容をcat に入力することができる.
code:▼はEnter,■はプロンプト
$ cat < file1▼
aaa
This is file1.
$ ■
上記の例ではfile1の内容が読み込まれ,標準出力(ディスプレイ)に出力(表示)されている.これは $ cat file1▼ とまったく同じ結果になる (だから現実にはあまり使われない) .
このように標準入力から他の入力元 (ほとんどがファイル) に切り替えることもまた,リダイレクションと呼ばれる.入力のリダイレクション記号は「<」が用いられる.応用として,標準入力と標準出力の両方をファイルに切り替えると,ファイルのコピーができる.
code:▼はEnter,■はプロンプト
$ cat < file1 > file6▼
$ cat file6▼
aaa
This is file1.
$ ■
この例では"<"によりfile1の内容がcatに入力され,">"によってfile6に出力されている.結果,file1の内容をfile6にコピーしたことになる.
なお,すでに述べたとおり,"<"で入力をファイルに切り替えることと,ファイルを引数として直接指定すること,つまり,
$ cat file1
と
$ cat < file1
とは同じ出力結果となる.ただし,結果が同じになるのは指定ファイルが1つの場合のみである.その理由を,実際に試して考えてみてほしい.
まとめ
cat コマンドの動作をまとめて解説すると次のようになる.
1. cat の引数としてファイルが複数指定された時
⇒ 指定ファイルを連結して出力
2. 出力先を標準出力(ディスプレイ)からファイルに切り替える
⇒ リダイレクション:記号は ">"
3. cat の引数としてファイルが1つだけの時
⇒ ファイル内容の表示
4. cat の引数としてファイルが指定されていない時
⇒ 標準入力からの入力状態 ⇒ Ctrl+Dで入力終了
5. 入力元を標準入力からファイルに切り替える
⇒ リダイレクション:記号は "<"
フィルタコマンドの使用方法
一般的に,入力されたデータを加工して出力するプログラムをフィルタコマンドと呼ぶ.フィルタコマンドには代表的なものとして,grep , head , tail , sort などがあるが,cat コマンドもフィルタコマンドに分類される.
フィルタコマンドには,引数にファイルが指定されなければデフォルト (既定値) として
入力=標準入力,出力=標準出力
という動作上のルールがある.たとえばcat コマンドを何の引数なしに
$ cat▼
としてもエラーとはならずにデフォルトの動作をする(どのような動作になるか各自で考えてみよう).
そしてこの動作ルールを利用して,フィルタコマンドはパイプを使ってつなぐことができる.「パイプ(パイプライン)」とは,一つのデータの流れに対し,複数の処理を逐次的に (リレーのように) つなげて行う仕組みである.Unixコマンドラインでのパイプ処理では,パイプ記号「|」(バーティカルバー)を使い,"|"の左側のコマンドの標準出力を,"|"右側のコマンドの標準入力に接続する.
$ コマンド1 | コマンド2 | コマンド3 …
この例ではコマンド1の標準出力=コマンド2の標準入力,コマンド2の標準出力=コマンド3の標準入力となる."|"の数はいくつでもかまわない.次の例を見てみよう.
$ cat file1 file2 | sort -r | head -n 5
この例ではfile1とfile2の内容が連結されてsort コマンド,head コマンドの順に流し込まれ,その結果が標準出力に出てくる.
パイプ処理を使うと,各コマンドの結果を保存する必要がなくなる.上の例を別々に行おうとすると,
code:▼はEnter,■はプロンプト
cat file1 file2 > temp1
sort -r temp1 > temp2
head -n 5 temp2
rm temp1 temp2
のようにtemp1,temp2などの一時ファイルを作成する必要がある.パイプを使った方があきらかに記述が簡潔であり,無駄なファイルを作らずに済み,結果として実際の動作速度も速い.
Unixコマンドの一般的な使用方法
以上,cat コマンドを中心に説明してきたが,これをUnixのコマンド一般に敷衍 (ふえん) してみよう.
一般的にコマンドはたいてい引数つきで実行されるが,引数の種類よって次のような一般形になる.
※[ ]の中は必要に応じて指定する
※オプションや主引数はすべて1つ以上の半角空白またはタブで離されていなければならない.
※これらの形式はPOSIXという規格に基づいている.また,拡張として,GNUスタイルとして"--"とハイフンを2つ繋げたあと,"help"など,意味がわかりやすい (結果的に長い) オプション表記をする方式がある.たとえばヘルプ提示オプションが"-h"だとすると,ロングスタイルは"--help"といった表記になる.本実習では使わなかったが,Unix系OSの多くのコマンドはPOSIXの短いスタイルとGNUスタイルの両方に対応している (例:grep --helpとやってみよう) . 引数は大まかに,コマンドの動作を条件づけるオプションを指定するものと,処理の対象として文字列やファイル名などを指定する,いわば「主引数」に分けることができる (※主引数という呼び名はここだけのもの) .通常,オプションの指定は「-」(マイナス記号)をつける.オプションにも引数を与えることがある.文字列は「'」(シングルクォーテーション)で囲むと,文字列であることを明示することができる.ファイル名はほとんどの場合クォートせずにそのまま与える.
コマンドによっては引数を必要としないもの,逆に必ず処理対象を指定しなければならないもの,どちらでも動作するものがある.オプションも同様である.
lsコマンドを例にとると,
code:lsの例
$ ls (オプション・引数なし⇒デフォルト動作)
$ ls –l Dir1 (オプション"l"を指定,対象はDir1を指定)
$ ls –lR Dir1 Dir2(オプション"l"と"R"を指定,対象はDir1とDir2を指定)
など,柔軟な引数指定が可能である.
Unixの考え方
これまで説明してきたことは,Unixでよく使われるコマンドの基本形に過ぎない.Unixには非常に数多くのコマンドがあるので例外も数多く存在する.しかし,パイプやリダイレクションはUnixコマンド個別の機能ではなく,「シェル」というコマンドインタプリタの機能なので,これをサポートしているプログラムはすべて,パイプでつなげることが可能である.
※シェルで繋げられたコマンド群は,「カーネル」と呼ばれる内部システムとメッセージをやりとりして各々の仕事をこなす.
このシェルはUnixのすぐれた設計の1つで,ユーザとカーネルをとりもつインタフェースであり,次のような特徴をもつ.
a. パイプやリダイレクションで表現されたコマンドライン入力を,1つの大きな「コマンド」として実行できるように,カーネルに引き渡す
b. コマンドラインでの作業を効率化するための,コマンドエイリアス,ヒストリ,ファイル名補完機能等がある
c. ユーザの作業環境をかなり自由に設定できる
d. 多くのコマンドを組み合わせ,条件分岐や繰り返しなどを含む,シェルスクリプトという一種のプログラムを作り実行できる
e. シェルはデフォルトに採用されているもの以外にも何種類もあり,ユーザの好みと必要に応じて変更したり使い分けることができる
※現在のUnix系OSのデフォルトシェルはほとんどが"bash"である.MacOSは"zsh"(bash上位互換シェル)である.
シェルに見られるこれらの柔軟な機能こそ,"Small is beautiful"というUnixの設計思想の反映だといえる.Unixの設計者たちはカーネルとシェルを分けて構成し,Software Toolsと呼ばれる小さな単機能のコマンドを数多く用意し,それをパイプやシェルスクリプトによって組み合わせて活用し,ユーザの様々な用途に柔軟に対応できるように考えてきた.
この考え方は,最も初期のUnixから50年の時を経て,LinuxやBSDあるいはMacOSやAndroidなど,さまざまな形態に分岐した現在もなお受け継がれ,その成果として巨大なネットワークを支えるサーバシステムやSaaS,IaaS等のクラウドシステムを生み出し,スマホの対話システムやロボットの制御装置,IoTの埋め込み ( エンベディッド ) 型のSoCに至るまで,極めて広い範囲に応用されている.
これは,ユーザアプリケーション中心に,だれもが同じものを使えるように,より大きく重く,分離不可能な形で発展してきたWindowsとは大きく異なるものである.それはどちらが優れているかという単純な事ではないが,コンピュータの歴史の大きな一側面を形作ってきたのがUnixとその設計思想であるという事は疑う余地がない.このことをぜひ,認識しておいていただきたい.
以上.
2023/7/20 改訂 by Kobori Satoshi, Fujii Daisuke