1. まともな OS には階層がある
コンピュータに触れるとき、ユーザの相手をしてくれるのがシェル (ログインシェル) です。2.「OS ではない OS」と「OS な OS」がある
実はコンピュータの OS はいくつかの階層に分かれて作られており、高度な OS であるほど階層が多くなっています。
OS の簡易階層図ユーザと OS の間にアプリケーションが存在し、シェルはアプリケーションとして動作します。
*1「アプリケーションソフトウェア」の略。最近はさらに短縮されて「アプリ」と呼ばれる。
ユーザ ユーザがアプリケーション*1を通してコンピュータを操作する アプリケーション ユーザが作成したプログラム。プログラミング言語・ゲーム・ワープロ・Web サーバ 等 ← シェルはここ OS ライブラリ アプリケーションから発行される命令に従って動作する便利プログラムの集合体 カーネル 短い間隔 (1/100秒以下) で常にハードウェアを監視し、他から要求があればハードウェアを操作する ハードウェア CPU・メモリ・ハードディスク・時計・ディスプレイ 等
ユーザが操作するのはアプリケーションであり、直接に OS やハードウェアを操作することはありません。
もし OS やハードウェアを操作する必要があれば、アプリケーションやライブラリのプログラムを作ることになります。
日常的に Linux を使っていますが、これを OS と呼んでいると思います。3. シェルは内臓を隠すもの
屁理屈的なことを言うと、これは「ディストリビューション」(意味: 配布物) であり、OS ではありません。
Linux とは上記簡易階層図の「カーネル」部であり、ライブラリやアプリケーションが同梱され「ディストリビューション」となって配布されています。
OS を便利に使おうとすると様々なソフトウェアが必要になり、それぞれの作者には当然の主張があるため、こうならざるを得ません。
Linux ディストリビューションの例 (ほかにもたくさんあります)
一方、Solaris は OS です。オラクルという会社が販売しています。
- AlmaLinux
- LockyLinux
- Fedora
- RedHat
- Debian
- Ubuntu
オープンソースの OpenIndiana (OpenSoaris の後継) もあり、こちらはディストリビューションです。
シェルにもいろいろありますが、多くの人は「便利なツール」「よくわからないけど必要なもの」という認識だと思います。4. REPL って何?
その認識はだいたい合っています。
シェル (Shell: 貝殻) はなぜそう呼ばれているかというと「脆弱な内臓を覆い隠す」という意味があるからだそうです。
ユーザがコンピュータを操作するとき、カーネルやハードウェアを直接操作すると OS 内部の知識が必要なだけでなく、
本来の目的を果たすために多くの手順を踏まなければならない上に、少しでも間違えると意図しない悪影響を引き起こします。
そんなことをさせないよう、ユーザがやりたいことを簡素かつ直感的にコンピュータに伝えるための道具がシェルです。
ファイルをコピーしたいだけなのに、いくつものシステムコールやデバイス番号、必要なバッファの計算等を逐一考えたくないのです。
OS という内臓を覆い隠すことにより利便性を向上させているため、初めて触れる人にとって「よくわからない」のは当然です。
シェルに対しての「よくわからない」が「よくわかった」になったとき、それはシェルを理解しただけでなく OS も理解したことになります。
シェル自体がどんどん高機能になって「便利なツール」になっています。
多くの Linux ディストリビューションの標準シェルは Bash です。(Solaris11, OpenIndiana も Bash)
シェルは REPL とも呼ばれています。5. ここはどこ?私は誰?
REPL は本来、インタプリタ (プログラミング言語) のひとつの機能の呼び方です。(由来は Lisp 言語から)
の頭文字を並べたもので 1,2,3 を順に実行し、これを繰り返します。
1. Read … 読み込み 2. Eval … 評価 3. … 出力 Loop … 繰り返し
1. ユーザからの命令を受け付け、すべてのシェルをインタプリタとみなして良いかどうかはわかりませんが、
2. 受け付けた命令を実行し、
3. 実行結果をユーザに返す。
…を永遠に繰り返す、という意味です。
少なくとも Bash はスクリプトを使ったバッチ処理 (一括処理) が可能なうえ、
プログラミング言語の一覧にも掲載されているので、REPL と呼んでも構わないでしょう。
REPL の機能を有するプログラミング言語なら、シェルとして動作することができます。
(REPL の機能がないプログラミング言語も沢山あります)
OS にユーザ ID とパスワードを打ち込んでログインすると、出迎えてくれるのがシェルです。これをログインシェルと呼びます。6. ログインシェルは Bash だけ?
自分のログインシェルは何になっているでしょうか?管理者に嫌われてなければ Bash になっていると思います。
(Linux はかなり昔から Bash。Solaris は 11 でユーザシェルが Bash になりました)
ログイン直後に以下を実行し、その下の実行結果と同じなら Bash になっているでしょう。*2
$ echo $0打つのが面倒だけど、こうやっても確認できます。(他人のも確認できます)
bash
$ echo $SHELL
/bin/bash
*2この変数は Bash 自体が名乗っているため、実はあてになりません。
Bash 以外で ps のようなプログラムを呼び出せば確実ですが、OS の知識が必要となるのでここでは割愛します。
$ cat /etc/passwd | grep '自分のユーザID' | cut -d ':' -f 7
/bin/bash
一番有名なログインシェルは Bash です。ほかにも sh(Bourne Shell)、csh(tcsh)、zsh 等があります。7. アプリケーションを起動するアプリケーション
文法が異なりますが概念はほぼ一緒なので、これらに変更しても戸惑うことはあまりないでしょう。
(概念が一緒なら、変更する必要がないともいえる)
REPL の機能があれば何でもログインシェルにできるため、
(変態と呼ばれても構わないなら) Python や Node.js をログインシェルに指定することもできます。
• Python をログインシェルにした場合 (ちょっと変態)
• Node.js (JavaScript) をログインシェルにした場合 (まだ人間に戻れる)$ cat /etc/passwd | grep 'python-mania' | cut -d ':' -f 7
/bin/python
ユーザ python-mania としてログイン (ログアウトは + をタイプする)
Python 3.9.18 (main, Jan 4 2024, 00:00:00) [GCC 11.4.1 20230605 (Red Hat 11.4.1-2)] on linux Type "help", "copyright", "credits" or "license" for more information. >>> print('Hello, Python') Hello, Python >>>
組み込み用マイコンボードの Raspberry Pi Pico では推奨シェル (REPL) が Python (MicroPython) になっています。
• PHP をログインシェルにした場合 (そろそろヤバい)$ cat /etc/passwd | grep 'js-mania' | cut -d ':' -f 7
/bin/node
ユーザ js-mania としてログイン
Welcome to Node.js v16.20.2. Type ".help" for more information. > console.log('Hello, Node.js') Hello, Node.js undefined > .exit
世間では PsySH が話題のようだが、ここは敢えて PHP のインタラクティブモード。(せめて EPEL に入ったら考える)• ド変態 (賞賛) の場合 (ああ、何ということだぁ…)
$ su
# echo '#!/bin/php -a' > /bin/php-a
# chmod +x /bin/php-a
# exit
$ cat /etc/passwd | grep 'php-mania' | cut -d ':' -f 7
/bin/php-a
ユーザ php-mania としてログイン
Last login: Fri Nov 1 15:16:13 2024 from 192.168.1.11 Interactive shell php > echo "Hello, PHP\n"; Hello, PHP php > exit
$ cat /etc/passwd | grep 'pl-mania' | cut -d ':' -f 7
/bin/gprolog
ユーザ pl-mania としてログイン
GNU Prolog 1.5.0 (64 bits) Compiled Jul 21 2022, 00:00:00 with gcc Copyright (C) 1999-2021 Daniel Diaz | ?- write('Hello, Prolog'). Hello, Prolog yes | ?- system('pwd'). % No, you should love solitude. /home/pl-mania yes | ?- halt.
Bash は非常に偉い誰かが作ったアプリケーションです。8. 直前に実行したコマンドをシェルスクリプトにしてみる
非常に有用で便利ですが、すべての機能があるわけではありません。
例えば C コンパイラや Web サーバの機能は Bash にありません。
C コンパイラや Web サーバは複雑で巨大なアプリケーションなので、これを使用しないユーザにとっては邪魔になります。
Bash は、自分を無駄に高機能にしない代わりに、ほかのアプリケーションを起動させることができます。
その時々に応じてエディタやコンパイラ、その他 (Python 等) のインタプリタ等を呼び出すことにより、複雑な動作を実現します。
例えば、ファイルを送受信するなら ftp や scp、wget コマンド (命令) を、
他のサーバで作業をこなしたい (リモートジョブ) なら ssh や telnet コマンドを、
シェルから適宜に呼び出します。
例: www.example.jp と news.example.jp の Web ページを取得するスクリプト。
ファイル名: web-get-sample.sh
wget コマンドを 2 回呼び出している。
#!/usr/bin/bash wget http://www.example.jp/ -O toppage.html wget http://news.example.jp/ -O newspage.html
Bash もアプリケーションのひとつなので、Bash から Bash を起動させることができます。
ファイルや標準入力を指定すればインタプリタとして動作し、指定しなければ REPL として動作します。
• スクリプトファイルを作成して Bash に実行させた場合 (インタプリタとして実行)
$ cat > ./example.sh << EOF• 標準入力から Bash へスクリプトを送り込んだ場合 (インタプリタとして実行)
A=1
B=2
echo \`expr \$A + \$B\`
EOF
$ cat ./example.sh
A=1 B=2 echo `expr $A + $B`
$ bash ./example.sh
3
$ echo 'A=1 ; B=2 ; echo `expr $A + $B`' | bash• 何も指定せず Bash を起動した場合 (REPL として実行)
3
$ bash
これはログインした状態と同じ。
$ A=1 $ B=2 $ echo `expr $A + $B` 3 $
「Linux のコマンドはずいぶん使えるようになったけど、スクリプトはいまいち…」
…という人が居るかどうか知らないけど、Bash には history コマンドがあります。
これを使って、実行したコマンドをスクリプトファイルにできます。
8-1. 必要なコマンドを普通に実行する。(ここでは、必要ないコマンドも混ぜてます)
$ # カンケーないコマンド8-2. history コマンド
$ A=1
$ B=2
$ echo `expr $A + $B`
3
$ # カンケーないコマンド
Bash に組み込まれている history コマンドは、過去に自分が実行したコマンドを表示します。8-3. コマンドだけを取得する。
オプションに数値を指定すると、直近の数行だけを表示します。
ここで直近の 5 行を指定して history コマンドを実行すると、以下になります。
$ history 5
行頭の数字は、実行されたコマンドの順番を示しています。
11 # カンケーないコマンド 12 A=1 13 B=2 14 echo `expr $A + $B` 15 # カンケーないコマンド
行頭の数値が邪魔なので削除すると、実行したコマンドを得られます。8-4. スクリプトファイルを作る。
('' は空白文字です。分かりにくいので色をつけています)
$ history 5 | cut -d ' ' -f 3-
実はちょっと嘘が入ってる: すでに上記 8-2 で history を実行しているため、本当は行数がズレる。
# カンケーないコマンド A=1 B=2 echo `expr $A + $B` # カンケーないコマンド
上記 8-3 をファイルにリダイレクトしてテキストエディタで成形すれば、スクリプトファイルの完成。
$ history 5 | cut -d ' ' -f 3- > ./example.sh
$ vim ./example.sh # ← 必要ないコマンドをテキストエディタで削除する。
$ cat ./example.sh
A=1 B=2 echo `expr $A + $B`
実行してみる
$ bash ./example.sh
3