講座概要 + シェル
動機
コンピュータサイエンスに携わる者として私たちは、コンピュータが繰り返し作業をこなすのに素晴らしい助けとなることを知っています。しかしこのことが、私たちがプログラムに実行させたい計算に対して当てはまるのと同様に、コンピュータの 使い方 にも当てはまることは、殆どの場合に忘れられています。私たちの手元にはいとも簡単に使いこなせる膨大な量のツールがあり、それらは、コンピュータにまつわるどんな問題に取り組んでいようとも、私たちの生産性を高め、より複雑な問題を解くことを可能にしてくれるのです。にもかかわらず、私たちの多くはこうしたツールのうち、ほんの一握りしか使いこなせていません。なんとかやり過ごすのに必要十分な魔法の呪文を暗記し、詰まったときにインターネットで調べたコマンドを盲目的にコピペしているに過ぎないのです。
この講義では、こうした課題の解消を試みます。
私たち講師陣が企図しているのは、どうやったら既知のツールを最大限使いこなせるかを教え、新しいツールを提示してあなた方自身の道具箱に加えてもらい、願わくば自力でより多くのツールについて探求すること(や、ひょっとしたらそれらを作成すること)の興奮を体感してもらうことです。こうしたことが、ほとんどのコンピュータサイエンスのカリキュラムで不足していると考えています。
講座の進め方
本講座は1時間の、全11回の講義からなり、それぞれの講義で個別のトピックを中心に据えます。各講義は大部分において独立していますが、学期が進むにつれて、それまでの講義内容については習熟しているものとして取り扱います。講義ノートはオンラインで展開しますが、教室で展開される内容(例えば、デモ形式のもの)の多くは講義ノートに含まれないかもしれません。講義は録画され、オンラインで投稿される予定です。
11回の1時間講義からなる講座でたくさんの領域を取り扱おうとしていることから、各講義はそこそこ濃密なものになります。自分のペースで講義内容に習熟する時間を設けてもらうために、各講義ではポイントを押さえるための実習問題を設けています。各講義の後にオフィスアワーを設定しており、そちらで持ちうる疑問に答える助けとなるべく、講師陣が待機しています。この講座にオンラインで参加している場合は、質問をこちらのメールアドレス missing-semester@mit.edu に送ってください。
時間が限られている都合上(訳注: 本講座は Independent Activities Period という1ヶ月の特別学期にて開講されている)、ツール全てについて、通常学期の講座と同じ粒度で取り上げることは不可能となります。可能な限り、ツールやトピックについてより深く知るための情報源を示すようにしますが、もし特別に興味を引くものがあったならば、躊躇なく私たちを捕まえて、ヒントを仰ぐようにしてください!
最初のトピック: “シェル”
シェルとは何か
今日のコンピュータはユーザがコマンドを入力するための多様なインターフェースを備えています。奇抜なグラフィカルユーザーインターフェース、ボイスインターフェース、加えてARやVRまでもが、そこかしこにあります。これはユースケースの80%においては素晴らしいことなのですが、これらのインターフェースは私たちがコンピュータを通じて実現できることについて、しばしば根本的な部分で制約を課すことになります。例えば、そこに存在しないボタンを押すことは出来ないですし、また、事前にプログラムされていないボイスコマンドは受け付けてもらえません。コンピュータが提供するツール群を最大限使いこなすためには、伝統的なやり方に則って、テキストベースのインターフェースに目線を下げる必要があります。それがシェルです。
あなたが手に取りうるほぼ全てのプラットフォームは何らかの形式でシェルを備えており、そのうちの多くでは複数のシェルの中からユーザが選択したものを利用できるようになっています。それらのシェルでは細部に様々な違いがある一方で、核心においてはおよそ同じです。つまりシェルというものは、ユーザにプログラムを実行させ、プログラムへ入力を渡し、プログラムの出力を部分的に構造化された方法で点検します。
この講義では “Bourne Again SHell”、短くは “bash” と呼ばれるシェルについて焦点を当てていきます。このシェルは最も普及しているものの一つで、その記法は多くの他のシェルのものと似ています。シェル プロンプト (あなたがコマンドを入力できる場所です)を開くには、まず ターミナル が必要となります。あなたのデバイスには出荷時にシェルがインストールされているかもしれませんし、さもなくば、そこそこ簡単にインストールできます。
シェルを使う
ターミナルを起動したら、だいたいこのような プロンプト を目にすることになります:
missing:~$
これがシェルに対するテキストベースの主インターフェースとなります。これが意味するのは、あなたが missing
という装置を操作していること、あなたの「カレントワーキングディレクトリ」あるいは今いる場所が ~
(”home” の縮約形)であることです。ここの $
はあなたがいわゆるルートユーザ(後述)ではないことを示しています。このプロンプトにて、あなたは コマンド を入力することができます。そしてそのコマンドは、シェルによって解釈されます。最も基本的なコマンドは、プログラムの実行です。
missing:~$ date
Fri 10 Jan 2020 11:49:31 AM EST
missing:~$
ここで私たちは date
と呼ばれるプログラムを実行しました。あまり驚くこともないかもしれませんが、このコマンドは現在の日付と時刻を出力します。これを受けてシェルは、次に実行するコマンドは何か尋ねます。このように、コマンドに 引数 を与えて実行することも可能です。
missing:~$ echo hello
hello
ここではシェルへの命令として、 echo
というプログラムに hello
という引数を与えて実行するように伝えました。この echo
プログラムは単に引数を画面に表示するものです。シェルは、受け取ったコマンドを空白文字で分割して解釈した上で、最初の単語が示すプログラムを実行し、続く単語を各々、そのプログラムに引数として渡します。もし引数にスペースや他の特殊文字(例えば ”My Photos” というディレクトリ名)を渡したい場合は、引数を '
か "
でくくるか(例えば "My Photos"
)、\
を用いてそれらの文字をエスケープすることができます(例えば My\ Photos
)。
しかし、シェルはどうやって date
や echo
といったプログラムを探すのでしょうか。いいでしょう、シェルはちょうど Python や Ruby のようなプログラム環境であり、したがって、変数、条件文、ループ、そして関数(次の講義で触れます!)を備えているのです。シェルでコマンドを実行する際、実はあなたは少量のコードを書き、シェルがそれを解釈しているのです。もし予めプログラムされたキーワードに一致しないコマンドの実行を依頼された場合、シェルは $PATH
と呼ばれる 環境変数 に問い合わせ、そこで列挙されるディレクトリを参照して、コマンド受付時のプログラム検索対象として利用します。
missing:~$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
missing:~$ which echo
/bin/echo
missing:~$ /bin/echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
echo
コマンドを実行すると、シェルは echo
というプログラムを実行する必要があると考え、その上で $PATH
にある :
で区切られたディレクトリ群を echo
という名前で検索します。検索対象を発見したら、シェルはその対象を実行します(前提としてそのファイルが 実行可能 である必要があります;後述)。プログラム名に応じたファイルの場所を調べるには which
プログラムを使います。その結果として判明した実行ファイルへの パス を用いることで、$PATH
を使わずに済ませることもできます。
シェル上で移動する
シェル上のパスは、特定文字で境界が定義された、ディレクトリが並べられたものになっています。その特殊文字は、 Linux と MacOS では /
であり、 Windows では \
です。Linux と MacOS における /
ディレクトリは、そのマシンが持つファイルシステムの「ルート(訳注: 根本、根底の意)」であり、全てのディレクトリとファイルがその下に置かれています。他方で Windows では各ディスクパーティションごと(例えば、 C:\
)に一つのルートが存在しています。この講座では、 Linux ファイルシステムが利用されている前提で話を進めます。 /
で始まるパスは 絶対 パスと呼ばれています。他方、それ以外の如何なるパスも 相対 パスだということになります。相対パスは、カレントワーキングディレクトリからの相対的な位置を示しています。カレントワーキングディレクトリは、 pwd
コマンドで確認可能で、 cd
コマンドで変えることができます。パスにおける .
は現在いるディレクトリを、 ..
はその親ディレクトリを表します。
missing:~$ pwd
/home/missing
missing:~$ cd /home
missing:/home$ pwd
/home
missing:/home$ cd ..
missing:/$ pwd
/
missing:/$ cd ./home
missing:/home$ pwd
/home
missing:/home$ cd missing
missing:~$ pwd
/home/missing
missing:~$ ../../bin/echo hello
hello
シェルプロンプトがカレントワーキングディレクトリの在り処を常に示していることに気づいたでしょうか。プロンプトの設定を変えることで、様々な便利な情報を表示できるようになります。その方法については、別の講義で取り上げます。
原則、プログラムを実行する際、敢えて異なる指示をしない限りは、今いるディレクトリにおいて作業がなされます。例えば、プログラムは今いるディレクトリでファイルを検索し、必要であればそこで新しいファイルを作成します。
特定のディレクトリに何が在るかを見るためには ls
コマンドを使います。
missing:~$ ls
missing:~$ cd ..
missing:/home$ ls
missing
missing:/home$ cd ..
missing:/$ ls
bin
boot
dev
etc
home
...
ディレクトリ名が第一引数として渡されない限り、 ls
コマンドは今いるディレクトリの内容を表示します。ほとんどのコマンドは -
で始まるフラグとオプション(値を伴うフラグ)を受け付け、結果としてコマンドの振る舞いを変えることができます。大体の場合、 -h
か --help
フラグを渡してプログラムを実行すれば、どんなフラグやオプションが使えるかのヘルプ文が表示されるでしょう。例えば ls --help
を実行すると以下のように表示されます。
-l use a long listing format
missing:~$ ls -l /home
drwxr-xr-x 1 missing users 4096 Jun 15 2019 missing
これは、今ある各ファイルやディレクトリについて遥かに多量な情報をもたらしてくれます。まず行頭の d
は missing
がディレクトリであることを教えてくれます。続いて、3文字(rwx
)が3つずつ並んでいるのに注目してください。これは対象に対して、ファイルの持ち主(missing
)、所有ユーザグループ(users
)、それ以外の全員が各々どういった権限を持つかを示しています。この中で -
は該当者が当該権限を持っていないことを意味しています。上記では、所有者のみが missing
ディレクトリを編集(w
)可能で、例えばこのディレクトリにファイルを追加したり削除したりできます。ディレクトリに入るには、ユーザは該当ディレクトリとその親ディレクトリに対して「検索」権限(「実行 execute」と表現される: x
)を持っている必要があります。ディレクトリの内容を列挙するには、そのディレクトリに対して読み取り(r
)権限を持っている必要があります。ファイルに対しては、上記から推測されるような権限となっています。 /bin
ディレクトリに在るほぼ全てのファイルで、最後のグループ、つまり「全員」に x
権限が設定されていることに気づいたでしょうか。結果として、誰でもこれらのプログラムを実行することが可能となっています。
他の手軽なプログラムで現時点で知っておいたほうが良いのは、 mv
(ファイル名を変えたり、ファイルを動かす)、 cp
(ファイルをコピーする)、そして mkdir
(新規ディレクトリを作成する)です。
プログラムの引数、入力、出力、あるいは動作の仕組み一般について もっと 情報がほしいと思ったならば、 man
プログラムを試してみてください。これはプログラム名を引数に取り、そのプログラムの マニュアルページ を表示します。表示をやめるには q
を押してください。
missing:~$ man ls
プログラムを接続する
シェルにおいて、プログラムに関連して2つの主要な「ストリーム(訳注: 流れ)」があります。入力ストリームと出力ストリームです。あるプログラムが入力を読み取ろうとする時、それは入力ストリームから読み取ることを、また同様に何かを表示する時、それは出力ストリームに表示することを意味しています。普通、プログラムの入力元と出力先は、いずれもターミナルとなります。つまり、キーボードが入力元であり、スクリーン画面が出力先です。しかし、これらのストリームは別の対象に振り向けることも可能なのです!
最も単純な、方向替えの形式は < file
と > file
です。これらを用いることで、プログラムの入出力ストリームをそれぞれファイルに振り向けることが可能になります。
missing:~$ echo hello > hello.txt
missing:~$ cat hello.txt
hello
missing:~$ cat < hello.txt
hello
missing:~$ cat < hello.txt > hello2.txt
missing:~$ cat hello2.txt
hello
加えて >>
を用いて、ファイルに追記することもできます。このような入出力の向き先変更がもっとも力を発揮するのは、パイプ を利用する時です。 |
演算子によって、一方の出力が他方の入力となるプログラム同士を「連鎖」させることができます。
missing:~$ ls -l / | tail -n1
drwxr-xr-x 1 root root 4096 Jun 20 2019 var
missing:~$ curl --head --silent google.com | grep --ignore-case content-length | cut --delimiter=' ' -f2
219
パイプをうまく使いこなす方法については、データ利用の講義でより詳細に取り扱う予定です。
即興で強力なツール
ほとんどの Unix 似のシステムでは、ある特別なユーザが存在します。「ルート」ユーザです。上記でファイルを列挙する際に登場したのを覚えているかもしれません。ルートユーザはほとんど全てのアクセス制約にとらわれることなく、システムの中で如何なるファイルをも作成、読み取り、更新、削除することができます。普段はルートユーザとしてシステムにログインすることはしないでしょう。なぜなら意図せず、いとも簡単に何かを破壊できてしまうからです。代わりに、sudo
コマンドを使うことになります。その名前が示すとおり、スーパーユーザ、あるはルートとして実行する(訳注: “do something as su”)ことができます。権限エラーが返ってきたときの大半は、ルートとして何かする必要があることが理由です。ともあれ、本当にそのような手段を取る必要があるのか、事前に何重にも確認してください!
ルートとなって実行する必要があることの一つは、/sys
下にマウントされた sysfs
ファイルシステムへの書き込みです。sysfs
がいくつかのカーネルパラメータをファイルという形に落とし込んでくれているため、専用のツールを使うことなく、容易にカーネルの設定を変更することができます。注意: sysfs は Windows や MacOS には存在しません。
例えば手元のラップトップのスクリーン画面の明るさには、下記ディレクトリ配下の brightness
と呼ばれるファイル経由でアクセスすることができます。
/sys/class/backlight
このファイルに値を書き込むことで、スクリーン画面の明るさを変更できます。最初の直観ではこのようにやってみようと思うかもしれません。
$ sudo find -L /sys/class/backlight -maxdepth 2 -name '*brightness*'
/sys/class/backlight/thinkpad_screen/brightness
$ cd /sys/class/backlight/thinkpad_screen
$ sudo echo 3 > brightness
An error occurred while redirecting file 'brightness'
open: Permission denied
このエラーに驚くかもしれません。言われた通りに sudo
を使ってコマンドを実行したのに!これは、シェルについて知っておくべき重要な事柄です。すなわち、 |
、>
、<
のような作業は、個別のプログラムではなく シェルによって 行われるのです。 echo
などは |
について「知らない」のです。それらは、入出力が何であろうが関係なく、ただ入力から読み取って、出力へ書き出しているだけなのです。上記の場合では、利用中のユーザとして認証された シェル が、 sudo echo
の出力とする以前に、書き込みのために明るさのファイルを開けようと試みます。その際、 sudo echo
の出力とすることは、シェルがルートとして実行されないために、阻止されます。この知見をもとに、この課題を解決するには以下のようにします。
$ echo 3 | sudo tee brightness
tee
プログラムが /sys
配下のファイルを書込み目的で開く役割を担い、それ がroot
として実行されるため、権限は全て正しく動作します。/sys
配下の、面白くて便利なものを全て制御することができます。例えば、様々なシステムLED群のようなもの(あなたの手元でパスは変わる可能性があります)があります。
$ echo 1 | sudo tee /sys/class/leds/input6::scrolllock/brightness
次のステップ
ここまでで、あなたは基本的な作業をこなすのに十分なシェルの利用法を知りました。必要なファイルを探したり、ほとんどのプログラムの基本的な機能を利用したりできることでしょう。次の講義では、より複雑な作業を実行したり自動化したりするのに必要な、シェルや多くの手頃なコマンドラインプログラムについて話す予定です。
実践課題
この講座の全ての講義では、一連の実践課題を設定しています。具体的な作業もあれば、「XとYというプログラムを試しに使いなさい」といった自由課題もあります。いずれにせよ、これらの課題に取り組むことを強くお勧めします。
これらの課題の正答例はありません。何か詰まってしまったことがあれば、その時点までに試みたことを添えてご自由にメールしてください。私たち講師陣が助けになりましょう。
- この講座では、Bash や ZSH のような Unix のシェルを使う必要があります。もしあなたが Linux か macOS を使っているなら、特に何もする必要はありません。もし Windows を使っているなら、 cmd.exe あるいは PowerShell を実行していないことを確認する必要があります。代わりに Windows Subsystem for
Linux か、Linux の仮想マシンを使って Unix 方式のコマンドラインツールを利用できます。適切なシェルを使っていることを確認するために、
echo $SHELL
というコマンドを実行してみてください。もし/bin/bash
か/usr/bin/zsh
のような応答があれば、正しいプログラムを実行できていると言えます。 /tmp
というディレクトリの下にmissing
という新しいディレクトリを作成してください。touch
というプログラムについて調べてください。man
というプログラムが助けになります。touch
というコマンドを使って、semester
というファイルをmissing
ディレクトリの中に作成してください。- そのファイルに下記を一行ずつ書いてください:
#!/bin/sh curl --head --silent https://missing.csail.mit.edu
一行目は取り掛かるのに難しく感じるかもしれません。
#
は Bash でコメントを始めるのに必要で、!
はダブルクォーテーション ("
) 文字列の中であっても特別な意味を持つことを知っておくのは有効でしょう。 Bash はシングルクォーテーション ('
) 文字列をこれとは違って取り扱います: これらがここで思いも寄らない働きをします。詳しくは Bash の quoting マニュアルページを見てください。 - 試しにこのファイルを実行してみてください。例えば、
./semester
のようにスクリプトへのパスを入力して、エンターキーを押してください。ls
の実行結果に頼るとなぜ失敗するのか理由を考えてみてください。(ヒント: そのファイルの権限ビットを確認してみましょう。) - 明示的に
sh
インタープリタで始め、ファイル名semester
を第一引数として渡してください。例えばsh semester
というように。./semester
では動かなかったのに、なぜこのやり方だと動くのでしょうか。 chmod
プログラムについて調べてください。( 例えばman chmod
)chmod
を使ってsh semester
と入力する代わりに./semester
として実行できるようにしてください。このファイルがsh
を使って解釈されるべきであることは、シェルはどうやって知るでしょうか。詳しくは、 shebang についての記事を見てください。|
と>
を使って、semester
プログラムによって最終修正日時を出力し、その結果をあなたのホームディレクトリにあるlast-modified.txt
というファイルに書き込むようにしてください。- ラップトップの電池の電力残量か、デスクトップ機のCPU温度を
/sys
から読み出すコマンドを書いてください。 注: macOS ユーザは、 sysfs がOSに組み込まれていないため、この課題は飛ばして良いです。
Licensed under CC BY-NC-SA.