はじめに
- コマンドを入力する
- コマンドの実行結果を出力する
これらを行うためのインターフェースを提供するソフトウェアを 端末エミュレータ という。
端末エミュレータとしてよく知られているアプリケーションには macOS の ターミナル がある。
「ターミナル」という用語は、本来「端末(terminal)」を指すが、現在では「端末エミュレータ」を指して使われることが多い。
また以下の用語は歴史的に用途や形が大きく変化してきたため、現代では使う人の文脈や背景知識によって異なるものを指したり連想されたりすることが多い。
かつての端末(TTY)
Terminal
「端末」という用語自体は広い概念であり、一般的にはユーザがシステムと対話するための入出力インターフェース全般を指す。
英単語の terminal には、コンピュータ用語の他に「末端の、終着駅」という意味がある。
- タイプライタ(入力装置)
- プリンタ(出力装置)
から構成される物理的な装置を 端末 と呼ぶ。
出典:Dominic Alves from Brighton, England - ASR 33 Teletype, CC 表示 2.0
https://commons.wikimedia.org/w/index.php?curid=4259023による
英訳が terminal なので混乱してしまうが、ここでの「端末」はアプリケーション(ソフトウェア)のターミナルのことではなく、ハードウェアの端末装置を指す。
端末自身は CPU やメモリなどの計算能力を持たず、文字の入力受付や印字などといった接続された大型コンピュータとのデータ送受信のみを行う、シンクライアント的な存在であった。
コンピュータが小型化して普及すると同時に、物理的な端末装置を模倣した 端末エミュレータ と呼ばれるアプリケーションがコンピュータ自体に搭載され、これに置き換わっていった。
端末はコマンドを解釈しない
現代で「入出力装置」と言えば、キーボードとディスプレイであるが、かつてはタイプライタとプリンタ(印字機)であり、この時代の端末は TTY(teletypewriter) と呼ばれた。
かつてのコンソール
コンピュータ初期のメインフレームと呼ばれる大型コンピュータは、キーボードとディスプレイで構成される 端末 に直接、接続されていた。
IBM - https://digitaltmuseum.no/011015240147/22-0-ibm-modell-360-370, CC 表示-継承 4.0
https://commons.wikimedia.org/w/index.php?curid=113477774による
特に、端末でオペレータ(管理者)が操作するための専用画面は コンソール と呼ばれた。
コンソールは CUI 環境であるため、ターミナル のようなウィンドウ、タブ、マウス操作という GUI 的な機能は備えていない。
出典:Jason Scott - Flickr: IMG_9976, CC 表示 2.0
https://commons.wikimedia.org/w/index.php?curid=29457452による
またコンソールは カーネルに直結している という大きな特徴を持つ。
かつてのコンピュータは起動時に「標準のコンソール」を決定するため、ケーブルを途中で抜き差しすることは想定されておらず、
- 1 台のコンピュータ
- 1 つの専属コンソール
- 1 人のオペレータ
といった対応関係で設計されていた。
現代のコンソール(仮想コンソール、TTY)
物理的な コンソール をソフトウェア化したもの。
かつてのコンソール同様に黒い画面であることには変わりないが、内部ではカーネルが /dev/tty1
〜 /dev/tty6
の デバイスファイル として管理していて、Ctrl + Alt + F1
〜 F6
で切り替えることができる(macOS のキー配列の場合 command + fn + F1
)。
仮想コンソールは、起動時にカーネルによってデバイスファイルとして作成される。
OS が起動すると、SysVinit
もしくは systemd
などの initシステム が getty
(get tty)プロセスを起動する。
getty
の役割は以下を行うことにある。
- デバイスとしての端末を
open()
する - シェルの標準入出力を
open()
した端末へ接続する - ユーザ名の入力を促すログイン用のプロンプトを表示する
-
login
プロセスを起動し、ユーザが入力した情報を渡すことでログインを実行する
getty
は /dev/tty1
、/dev/tty2
、 ... のデバイスファイルを システムコール open()
によってオープンし、戻り値として取得した ファイルディスクリプタ の接続先を次のように割り当てる。
ファイルディスクリプタ | 接続先 |
---|---|
0 (0 ) |
/dev/tty1 (キーボード) |
1 (標準出力) |
/dev/tty1 (画面出力) |
2 (標準エラー) |
/dev/tty1 (画面出力) |
これにより、シェルは 標準入力 を /dev/tty1
(キーボード)から受け取り、標準出力を /dev/tty1
(ディスプレイ)へと流せるようになる。
シェルの標準入出力の接続先は、 $ tty
コマンドによって確認できる。
$ tty
/dev/tty1
$ tty
/dev/tty2
getty
はその後、下記のようなログインプロンプトを表示し、ユーザー名から入力された「ユーザ名」と「パスワード」を login
プロセスに渡す。login
プロセスは getty
によって起動される。
login
プロセスはによる認証が完了すると、ユーザのデフォルトシェル(bash
など)起動する。
現代の端末 / 端末エミュレータ
Terminal Emulator
物理端末 をソフトウェアによって模倣(emulate)したアプリケーション。
- macOS の ターミナル
- Linux の GNOME Terminal
- Windows の コマンドプロンプト
などが代表的な端末エミュレータである。
(Windows の cmd.exe
は端末エミュレータに分類されるが、PowerShell は本来シェルでありながら独自の端末環境を提供する。一方、Windows Terminal はこれらをホストする端末エミュレータとして動作する。)
かつての物理端末と同様に、端末エミュレータ自体はコマンドの解釈や実行を行わない。
キーボードを介して、ユーザーからテキストの形式で入力されたコマンドを シェル に渡し、実行結果をシェルから受け取る。端末エミュレータの標準入出力は、ユーザが起動したアプリケーションとしてのターミナルプロセスが仲介しており、実際には 疑似端末(PTY) を通じてシェルと通信している。
コマンド入力という一面においては CUI による操作でも、実際にはウィンドウ、タブ、ペイン操作、マウス操作、コピー&ペーストなどができる GUI 環境上で動作している。Wikipedia ではこれを 「GUI 環境内で CLI(コマンドライン・インタフェース)を提供する」 と表現されている。
コンソール は完全な CUI 環境で動作するため、混同しがちな「ターミナルアプリ」と「コンソール」の大きな違いの一つがこの点にある。
デスクトップ環境のない環境では、端末エミュレータは存在しない。一方、デスクトップ環境のない環境でも仮想コンソールは存在する。
端末エミュレータは、複数のタブを開くことができ、タブごとにシェルを立ち上げることができる。
ウィンドウシステム を搭載している デスクトップ環境 では、アプリケーションとしての端末エミュレータを複数起動させることもできる。
各種製品が存在し、動作する環境や特徴が異なる。
端末エミュレータ | 環境 | 特徴 |
---|---|---|
ターミナル | macOS | macOS 標準搭載。 Bash や Zsh などのシェルへアクセスできる。 |
iTerm2 | macOS | サードパーティ製。 タブ分割、複数ペイン表示、ショートカットなどの機能、カスタマイズ性が豊富。 |
xterm | X Window System | Unix 系 OS(特に Linux)で利用される。 カスタマイズ性が低いが軽量で動作が軽く、基本機能に特化。 リソースが少ない環境や古いシステムでの使用に適している。 |
GNOME Terminal | X Window System | GNOME デスクトップ環境に標準搭載。 高度なカスタマイズ機能を持つ。 |
Windows Terminal | Windows | Windows 11 から標準搭載。 Windows 10 ではインストールが必要。 |
コマンドプロンプト | Windows | Windows 標準搭載。 |
端末エミュレータは、ローカルマシンの OS 上でシェルを動作させるだけでなく、SSH などを利用してネットワーク経由でリモート環境のサーバのシェルに接続し、操作する用途にも使われる。
擬似端末 / PTY
pseudo terminal
従来の 物理的な端末 を擬似的に再現した端末のこと。または端末エミュレータ上で論理的に分割された接続セッションのこと。
擬似端末(PTY)という概念を導入することで、1台のPC上で複数の端末(セッション)を並行して操作・利用することが可能になる。
擬似端末はカーネルによって /dev/pts/0
や /dev/pts/1
のような デバイスファイル として作成される。
PTY は マスター と スレーブ のペアによって構成される。
- マスター(Master)
- 指示を出したり、データを制御する側
- 端末エミュレータが操作する
/dev/ptmx
- 主従関係を表す用語が差別的であることから、現代では コントローラ と呼ばれることもある
- スレーブ(Slave)
- 指示を受けたり、データを処理・提供する側
- シェルが標準入出力として利用する
/dev/pts/N
ユーザからのコマンド入力は端末エミュレータからマスターに渡り、スレーブを経由してシェルへ送信される。
反対にコマンドの実行結果は、シェルからスレーブが受信し、マスターを経由して端末エミュレータに届けられる。
このように擬似端末は、仮想的に端末(TTY)をエミュレート(再現) しているにすぎない。
以下のコマンドで内部的に利用される。
ウィンドウシステム
グラフィカルユーザーインターフェース(GUI)を提供するための基盤となるソフトウェア。
以下の機能が提供される。
- ウィンドウの移動、サイズ変更などの管理
- 入力デバイス(マウス、キーボード)の管理
- グラフィック描画の管理
X Window System
主に Unix 系を中心とする OS で GUI を提供するシステムを X Window System(または X や X11 と言う)。
Linux では OS と一緒にインストールされることが多いが、技術的には OS に組み込まれているのではなく、独立したコンポーネント である。
X は クライアント - サーバ方式 を採用しており、以下のように分かれる。
-
X サーバー
- ディスプレイ、キーボード、マウスを管理する
- X クライアントからの描画要求を処理し、画面に描画する
- 入力デバイス(キーボードやマウス)のイベントを X クライアントに伝える
/usr/bin/Xorg
-
X クライアント
- ウィンドウの描画を要求するプロセス
- 一般的な GUI アプリケーション(例: Web ブラウザ、端末エミュレータ)
- X サーバに 「このウィンドウをここに描画してほしい」 といったリクエストを送る
- X サーバから入力イベントを受け取ってアプリの処理を行う
この方式により、X クライアント(アプリケーション)が ネットワーク経由で別のマシン上の X サーバーにウィンドウを表示させる(X転送)ことができる。
クライアントとサーバは Xプロトコル で通信を行うので、異なる OS、ハードウェア、アーキテクチャ(CPU)同士でも動作できる。
X 自体にはウィンドウの装飾や配置の機能はなく、これらは ウィンドウマネージャ と呼ばれる独立したプログラムによって提供される。さらに、デスクトップ環境 は、ウィンドウマネージャに加えてパネルやファイルマネージャなどを統合したものである。
また近年では、X に代わって Wayland という新しいプロトコルが登場している。
ディスプレイマネージャ
X Window System 上で動作するコンポーネント。
ユーザーがログインするための GUI ログイン画面の提供、セッションの管理を担当する。
ディスプレイマネージャは、ユーザー名とパスワードを入力するログイン画面を表示し、ログイン後には適切なデスクトップ環境やウィンドウマネージャを起動する。
ディスプレイマネージャ | 特徴 |
---|---|
XDM |
最も基本的なディスプレイマネージャ。 シンプルなログイン画面。 |
GDM |
GNOMEデスクトップ環境に標準搭載。 |
LightDM |
軽量で高速 Ubuntu のデスクトップ環境などで利用される。 |
systemd
が採用された環境では、systemd
が siaplay-manager.service
を起動する。
ウィンドウマネージャ
X Window System 上で動作するコンポーネント。
ウィンドウの配置、サイズ変更、移動、装飾(ボーダーやタイトルバー)などを管理する。
FVWM や IceWM、Openbox、Metacity など。
ウィンドウマネージャ | 特徴 |
---|---|
Metacity |
GNOME向けのウィンドウマネージャ。 シンプルで使いやすい。 |
KWin |
KDEで使用されるウィンドウマネージャ。 カスタマイズオプションが豊富。 |
i3 |
軽量で効率的なタイル型ウィンドウマネージャ。 キーボードでの操作性が重視されている。 |
Openbox |
軽量でカスタマイズ可能なウィンドウマネージャ。 デスクトップ環境に依存せず単独でも利用できる。 |
Wayland
Wayland も X と同様に クライアント - サーバモデル を採用しているが、X のように中央管理の X サーバは存在せず、コンポジタ(Compositor) がクライアントと直接通信する形になっている。
クライアントとサーバは Wayland プロトコル によって通信する。
これにより、X よりもシンプルで効率的な描画が可能になる。
Wayland では、ウィンドウの配置やタイトルバーの描画などの機能もコンポジタが直接管理するため、Wayland においてはウィンドウマネージャは存在しない。
代表的な Wayland のコンポジタ
- Mutter(GNOME 用)
- KWin(KDE 用)
- Weston(Wayland のリファレンス実装)
- sway(i3 風のタイル型 Wayland コンポジタ)
ターミナル
macOSに標準搭載されている 端末エミュレータ。
文脈によっては、端末エミュレータそのものを指す場合がある。
プロンプト $
/ %
/ #
prompt
端末エミュレータが提供するCLIにおいて、ユーザーに対して入力を促す文字列や記号。
prompt には「促す」と言う意味がある。
シェルの種類によって特別な意味を持つ場合がある。
プロンプト | 意味 |
---|---|
$ |
一般ユーザとしてログイン中であることを示す |
# |
スーパーユーザ(管理者)としてログイン中であることを示す |
% |
Zsh 等で利用される |
シェル
コマンドを解釈して、カーネルに対する システムコール を実行するソフトウェア。
GUI を持たず、端末エミュレータの CLI を介して利用することができる。
Windows の PowerShell のように、シェルが端末エミュレータと一体になっていて、明確に区別できない場合もある。
Bash、Zsh、sh など。
種類 | 特徴 |
---|---|
Bash | Unix系システムで広く使用される |
Zsh | 高度な機能とカスタマイズ性を持つ |
sh | 古いUnixシェルの一つ |
コマンドライン(cmd.exe ) |
Windowsコンソールホスト上で動作 MS-DOS由来のコマンドが多い |
Power Shell | コマンドラインの後継 GUIを持つため、端末エミュレータでもある オブジェクト指向 |
ログイン直後に起動されるシェルは ログインシェル と呼ばれる。
Bash
Bourne Again SHell
Unix系システムで広く使用されている標準シェル。
POSIX 規格に準拠しており、ほとんどのUnix系システムで動作する。
$ bash
シェルとしての Bash を起動するためのコマンド。
新しいシェルセッションが開始される。
$ bash
Zshを起動したターミナルから実行した場合、以下のような状態になる。
$ bash
The default interactive shell is now zsh.
To update your account to use zsh, please run `chsh -s /bin/zsh`.
For more details, please visit https://support.apple.com/kb/HT208050.
bash-3.2$ # ログインシェルがBashに切り替わる
bash-3.2$exit # 起動した Bash を終了する
指定したスクリプトを起動した Bash 上で実行することもできる。
$ bash スクリプトファイル
Zsh
Z Shell
高度な機能とカスタマイズ性を持つシェル。Bash と同様に POSIX 規格に準拠している。
近年の macOS のデフォルトシェル。
$ zsh
$ bash
と同様に、新しいシェルセッションを開始することができる。
$ zsh
$ zsh スクリプトファイル
sh
Bourne Shell
古くから存在するUnixシェルの一つで、他の多くのシェル(Bash、Zsh など)の基礎となっている。
「sh」と言う用語は、シェルスクリプトやコマンドを示すための一般的な総称として使われることがあり、Bash、Zsh、sh で記述されたスクリプトファイルの拡張子には .sh
が使用される。
POSIX
Portable Operating System Interface
IEEE によって策定される Unix 系OS間での互換性を保つための規格。
開発者目線では、POSIX規格に従って開発することでプログラムが異なるOS間で移植可能になる。また、Windows OS は POSIX には準拠していない(WSL といった技術は提供されている)。
さまざまなサブ規格に分かれている。
カーネル
Kernel
以下に挙げられるようなシステムの基幹となる制御を行う OSの中核 部分を担うソフトウェア。
ハードウェアとソフトウェアの橋渡し的な役割を持つ。
通常、アプリケーション(プロセス)は、カーネルから提供されるインターフェースを介してのみ、デバイスへのアクセスが許されている。
この制限によって、デバイスに複数のプロセスが同時にアクセスする場合でも、カーネルが競合するアクセス要求を調停するため、アプリケーション間でリソースの競合が起きない仕組みになっている。
カーネルがアプリケーションに提供するインターフェースや、機能を利用するために呼び出す命令または関数を システムコール 、スーパーバイザコール(SVC:supervisor call)という。このインターフェースは、ハードウェアの仕様の違いに依存しないように抽象化されている。
カーネルモード / ユーザモード
CPU の動作モードには、カーネルモード と ユーザモード がある。
カーネルモードは、その名の通りカーネルや、デバイスドライバなどのプロセスが動作するモードで 特権モード とも呼ばれる。
カーネルモードの CPU は、メモリ、I / O デバイスなどのハードウェアリソースに、制限なくアクセスを行うことができる。そのため、カーネルモードで不正な操作が行われたりバグが発生すると、メモリが破壊されたりデバイス動作が停止するといった、システム全体に影響が出る。
一方ユーザモードは、通常のアプリケーションプログラムが動作するモードであり、直接ハードウェアにアクセスを行うことができない。ユーザモードで動作するプロセスは、カーネルの提供するシステムコールを介してハードウェアにアクセスする。
システムコール
カーネルから提供される、プロセスがカーネルの特権的な機能を呼び出すためのインターフェース。
ユーザモード で動作中のCPUを、 カーネルモード へ遷移させる手段でもある。
システムコールの実行が終了すると、CPUはカーネルモードから再びユーザモードに戻ってプロセスの実行を継続する。
以下のような種類がある。
- ファイル操作:
open
,read
,write
- プロセス管理:
fork
,exec
,kill
- ネットワーク通信:
socket
,connect
システムコールを呼び出すことができるプログラミング言語は複数ある。
- C言語
- アセンブリ言語
- Rust
- Go
- Python
- C++
- Perl
- Ruby
- AssemblyScript / WebAssembly
C言語やアセンブリ言語は、OSやカーネル開発において主要言語として採用されることが多い。一方、PythonやPerlなどはシステムコールを直接呼び出す用途ではなく、ラッパーやモジュール経由で利用することが多い。
C言語には、glibc
と呼ばれる 標準Cライブラリ が存在し、この中にはシステムコールを内部的に呼び出すラッパー関数が含まれている。アセンブリ言語は直接システムコールを呼び出すことができるものの、アーキテクチャ ごとに存在するシステムコールを環境に応じて呼び分ける必要がある。C言語では glibc
のようなラッパー関数がアーキテクチャごとの違いを吸収するため、呼び出し側はその違いを意識する必要がない。
例外
プロセスがシステムコールを発行すると、CPU において 例外 が発生する。
この例外をトリガーにして、CPU は ユーザモード から カーネルモード へ遷移し、システムコールの処理を行う。
システムコールの処理が終了すると、CPU は再びユーザモードに戻り、プロセスを継続する。
標準Cライブラリ
C言語に標準で付属しているライブラリ。システムコール のラッパー関数が含まれる。
- 入出力操作(例:
printf
,scanf
) - メモリ管理(例:
malloc
,free
) - ファイル操作(例:
fopen
,fread
,fwrite
) - システムコールのラップ(例:
open
,read
,write
)
システムコール | 標準Cライブラリのラッパー関数 | 説明 |
---|---|---|
open |
open |
ファイルを開く |
read |
read |
ファイルやデバイスからデータを読み取る |
write |
write |
ファイルやデバイスにデータを書き込む |
close |
close |
ファイルを閉じる |
コマンド
シェルに対する命令。端末エミュレータ への入力を介して実行する。
コマンドの実体は実行可能ファイルであり、実行可能ファイルにはバイナリ形式とスクリプト形式がある。
コマンドの実体は実行可能ファイル
またその他にも以下の形式のコマンドもある。
実行可能ファイル(バイナリ形式)
ファイルシステム上に配置されたバイナリ形式の実行可能ファイル(実行権限 のあるファイル)は、コマンドとして実行することができる。
呼び出したシェルとは別プロセスとして実行される。
例:$ ls
、$ grep
、$ cat
実体はそれぞれ、/bin/ls
、/usr/bin/grep
、/bin/cat
などで、ファイルに拡張子は無い。「ビルトインコマンド」を内部コマンドと呼ぶのに対して、「バイナリ形式の実行可能ファイル」を 外部コマンド と呼ぶ。
Linux ではバイナリ形式の実行可能ファイルに拡張子はつけない。
バイナリ形式の実行可能ファイルは絶対パスで実行することもできるし、ファイル名だけでも実行できる。
$ /bin/ls
$ ls
ファイル名を与えただけでシェルがファイルを探し当てることができるのは、環境変数 $PATH
の存在があるためである。
$ ls
が実行された時、シェルはまず環境変数 $PATH
から ls
ファイルがないかを探している。
もし環境変数 $PATH
に /bin
が設定されていない場合には、シェルは ls
ファイルを見つけることができず、ファイル名だけでコマンドを実行することはできない。一方で、ビルトインコマンドは $PATH
を使用しないので、設定がなくても実行することができる。
※ 正確には下記の順に検索が行われる
- エイリアス
- ビルトインコマンド
- 環境変数
$PATH
なお、$PATH
にはカレントディレクトリを含めることができないため、カレントディレクトリ上の実行可能ファイルを実行するには ./
に続けてファイル名を指定する必要がある。
$ ./ファイル名
$ which
$ which コマンド名
$ which ls
/bin/ls
※ $PATH
に記載がないディレクトリにあるコマンドは表示されない
$ whereis
$ whereis コマンド名
$ whereis ls
ls: /bin/ls /usr/share/man/man1/ls.1
$ type
$ type コマンド名
$ type ls
ls is /bin/ls
$ type cd
cd is a shell builtin
$ kill
コマンドのように、ビルドインコマンドと実行可能ファイルの両方を持つものもある。
$ command
ビルトインコマンド と 外部コマンド を使い分ける際に利用される。
$ command
自体はビルトインコマンド。
同じ名前のコマンドにビルトインコマンドと外部コマンドがある場合、通常はビルトインコマンドが優先して使用される。
このようなとき、$ command
を利用することで明示的に外部コマンドを実行することができる。
$ command コマンド
他にも、外部コマンドと同名の エイリアス が設定されている場合に、エイリアスを無視して外部コマンドを優先して実行させることができる。
実行可能ファイル(スクリプト形式)
スクリプトファイルは実行権限を付与することで、スクリプト としてシェルから実行することができる。
コマンドとしてファイル名だけで実行させるためには、スクリプトファイルに読み取り権限(r
)と 実行権限(x
) を付与する必要がある。
$ ./スクリプトファイル名 # 読み取り権限と実行権限が必要
一方で、$ bash
や $ source
の引数に渡して実行する場合には、読み取り権限(r
)だけで実行できる。
$ bash スクリプトファイル
$ source スクリプトファイル
$ . スクリプトファイル
(コマンドの実体を理解するために、あえてバイナリ形式とスクリプト形に分類していますが、通常はコマンド実行者が「このコマンドはバイナリファイルなのか、スクリプトファイルなのか」などを気にする必要はありません。また、スクリプトファイルが実行権限エラーで実行できないと言う私自身の経験から権限の付与が必要であることを強調していますが、実行権限はバイナリファイルにも必要です。)
スクリプトの記述については こちら。
ビルトインコマンド
シェルに組み込まれたコマンド。内部コマンドと呼ばれることもある。
シェルによって直接実行されるため、呼び出したシェルのプロセス内で実行される。
$ cd
、$ pwd
、$ echo
、$ alias
、$ export
など。
$ type cd
cd is a shell builtin
バイナリ形式の実行可能ファイル とは異なり、環境変数 $PATH
上に実行可能ファイルを配置する必要がない。
関数
シェルスクリプトで定義した関数はコマンドのように実行することができる。
関数は $ function
によって定義し、$ unset
で削除することができる。
$ function say_hello() { echo "hello world"; }
$ say_hello
hello world
$ function
$ function 関数名() { 処理; }
$ 関数名() { 処理 }
※ function
で定義する場合、処理の末尾にはセミコロン ;
を記載する
エイリアス
既存のコマンドには エイリアス と呼ばれる「別名」をつけて実行することができる。
$ alias
登録済みエイリアスは $ alias
で表示することができる。
$ alias
新たにエイリアスを定義する際は、次のようにエイリアス名とコマンド名を =
で指定する。
$ alias エイリアス名=コマンド
$ alias hello='echo "hello world"'
$ hello
hello world
セミコロン ;
を使うと、複数のコマンドを集約させることもできる。
$ alias hello='echo "hello";echo "bye"'
$ hello
hello
bye
引数にエイリアス名を指定すると、エイリアスにしたコマンドを表示することができる。
$ alias エイリアス名
$ alias hello
hello='echo "hello world"'
$ alias
コマンドで登録したエイリアスは、現在のシェルセッションでのみ有効 であるため、永続的なエイリアスを登録したい場合、シェルの 環境設定ファイル に定義を追加する。
Bash を使用している場合 ~/.bashrc
という環境設定ファイルがシェル起動時に読み込まれているため、このファイルに以下の1行を追加しておくことで永続的なエイリアスを追加することができる。
alias hello='echo "hello world"'
編集した ~/.bashrc
ファイルは端末エミュレータを再起動するか、$ source
コマンドを使って、シェルに再読み込みさせることができる($ source
と $ bash
の違い )。
$ source ~/.bashrc
$ unalias
$ unalias エイリアス名
一時的にエイリアスを無効化する
既存のコマンドと重複するエイリアスが設定されている場合、通常はエイリアスの方が優先される。
/
をコマンドの前につけることで、エイリアスを一時的に無効化することができる。
$ /コマンド
コマンド置換
$()
でコマンドを囲うと、コマンドの実行結果を文字列に展開して、別のコマンドの引数として渡すことができる。
古い記法としてバックコーテーション ``
を利用した方法もあるが、可読性が低くなるため $()
の使用が推奨されている。
$ echo $(コマンド)
$ echo `コマンド` # 「`」はバックコーテーション
文字列中の変数の展開 同様に文字列内でも展開することができるが、シングルコーテーション内では展開されないため注意。
$ echo "ls: $(ls)"
$ echo "ls: `ls`"
$ echo '$(ls)' # コマンド置換されない
'
シングルコーテーションで囲った文字列中のコマンドは展開されない
複数のコマンドを続けて実行する
;
で複数のコマンドを続けて実行させることができる。コマンド実行結果にかかわらず、後続のコマンドは実行される。
$ コマンド1; コマンド2; コマンド3
&&
では、コマンドが正常終了した場合のみ、後続のコマンドが実行される。
$ コマンド1 && コマンド2 && コマンド3
||
では、コマンドが異常終了した場合のみ、後続のコマンドが実行される。
$ コマンド1 || コマンド2 || コマンド3
()
で複数のコマンドをまとめることもできる。
$ (コマンド1; コマンド2; コマンド3) && コマンド4
複数行のコマンド入力
複数行のコマンドを入力したい場合、行末にバックスラッシュ \
を記述する。
$ echo \
$ "hello world"
hello world
コマンド履歴
$ history
コマンドで履歴を表示することができる。
$ history
履歴番号 コマンド
で表示された履歴番号は、!
で指定して実行することができる。
$ !履歴番号
$ !!
$ !検索ワード
Bashの場合 ~/.bash_history
にコマンド履歴が保存され、保存できる履歴の最大数は環境変数 $HISTSIZE
、$HISTFILESIZE
で設定できる。
また、Ctrl
+ R
の同時押しでコマンド履歴を検索することもできる(reverse-i-search:逆順インクリメンタル検索)。
$ # Ctrl + R を押す
bck-i-search: _
検索モードからは Ctrl
+ G
もしくは Esc
で戻ることができる。
$ # ←ここに検索ワードを入力する
bck-i-search: _
検索にヒットした履歴は、再び Ctrl
+ R
を押すことでさらに過去のヒット結果に移ることができる。
履歴の位置は保存されるため、Ctrl
+ G
で検索を終了した時、↑
や ↓
を押すと、ヒットした履歴の位置からの表示になる。
$ eval
引数とした渡された文字列をコマンドとして実行するためのコマンド。
$ eval "コマンド"
シェル変数
ログイン中のシェルセッションでのみ有効な変数。
親プロセスから子プロセスへ引き継がれない。
宣言した変数は以下のように参照することができる。
$ 変数名=値
$ $変数名
$ hello=こんにちは
$ echo $hello
こんにちは
ビルトインシェル変数
シェルであらかじめ宣言されている変数。
ビルトインシェル変数 | |
---|---|
$? |
直前の実行コマンドの終了ステータス 成功の場合は 0 、失敗の場合 0 以外の値 |
$0 |
実行中のシェルの名前、もしくはコマンド名やスクリプトファイルのパス |
$# |
シェルスクリプト内で、スクリプトに渡された引数の数 |
$1 ,$2 ,$3 ... |
シェルスクリプト内もしくは関数内で、渡された引数が順に格納される(1番目は $0 ではなく $1 ) |
$* ,$@
|
シェルスクリプト内で、スクリプトに渡されたすべての引数を取得$* :一つの文字列として格納$@ :文字列の集合として格納(スペース区切り) |
$$ |
実行中のシェルのプロセスID |
$! |
最後にバックグラウンドで生成されたコマンドのプロセスID |
$PATH |
実行可能ファイル の検索パス(複数のパスが : で区切られた文字列として格納される) |
$HOME |
ユーザのホームディレクトリのパス チルダ ~ でも取得可能 |
$PWD |
現在の作業ディレクトリ |
$OLDPWD |
$ cd で移動する前の作業ディレクトリ |
$SHELL |
現在使用されているシェルのパス(/bin/bash 、/bin/zsh など) |
$LANG |
ロケール |
$PS1 |
プライマリプロンプトの定義 デフォルトでは \u@\h:\w\$ になっていることが多い\u :ユーザ名\h :ホスト名\w :現在の作業ディレクトリ\$ :ユーザ($ :一般ユーザ、# :root ユーザ)\s :シェルのなm |
$PS2 |
セカンダリプロンプト(複数行入力時の表示)を定義 デフォルトでは > になっていることが多い |
HISTFILE |
コマンド履歴を保存するファイルのパス デフォルト値: ~/.bash_history
|
終了ステータス / $?
直前の実行コマンドの終了ステータス。0
~ 255
が使用可能。
- 成功:
0
- 失敗:
0 以外
自作のスクリプトで終了ステータスを呼び出し元に返すには、exit
コマンドを使用する。
exit 0 # 正常終了(成功)
exit 1 # 異常終了(エラーなど)
これを利用して、異常が発生したらスクリプトを終了させることができる。
if [ $? != 0 ]; then
exit 1;
fi
エラー発生後に echo
コマンドで $?
を確認した場合、echo
コマンドの成否が $?
に再代入される点に注意。
$ cd not_exixts_directory
cd: no such file or directory: not_exixts_directory
# $? には cd コマンドの終了ステータスが格納
$ echo $?
1
# $? には echo コマンドの終了ステータスが格納
$ echo $?
0
変数の展開
変数を展開したい場合は、$変数名
もしくは ${変数名}
とする。
コマンドの引数、条件式、配列展開など、シェルスクリプトのさまざまな場所で適用することができる。
$ echo $変数名
$ echo ${変数名}
文字列リテラル中でも使用することができる。
$ echo "hello $変数名"
$ echo "hello ${変数名}"
ただし文字列リテラルで使用する場合、'
シングルコーテーションで囲った文字列中の変数は展開されないため注意)
'
シングルコーテーションで囲った文字列中の変数は展開されない
特に、パスのようにスペースを開けずに変数を使用したい場合は ${変数名}
を使用する。
$ hello=こんにちは
$ echo $hello
こんにちは
$ echo "$hello"
こんにちは
$ echo "$hello world"
こんにちは world
$ echo "$helloworld" # 変数 helloworld が未定義のため、何も出力されない
$ echo "${hello}world" # 変数に続いてスペースなしで文字列を使用する場合
こんにちはworld
$ set
$ set
コマンドを使用すると、実行中のシェル環境内で定義された全ての
- シェル変数
- ビルトインシェル変数
- 環境変数
を表示することができる。
$ set
-o
オプションによってシェルの機能を 有効化(-o
) / 無効化(+o
) することができる。
オプション + オプション引数 | 説明 |
---|---|
-o errexit |
コマンドがエラーを返した時に、即座にスクリプトを終了する |
-o nounset |
未定義の変数を使用した場合にエラーを発生させる |
-o xtrace |
実行するコマンドを表示(スクリプトのデバッグ用) |
-o verbose |
コマンドの内容をそのまま表示 |
-o noexec |
コマンドの実行をせずに構文チェックのみを行う |
オプション引数を指定しない場合、現在の設定を確認することができる。
$ set -o
$ unset
シェル変数、関数定義を削除する。
$ unset 変数名
$ unset 関数名
$ declare
変数に特定の属性(型や制約)を設定することができる。
$ declare 変数名=値
オプション | 説明 |
---|---|
-i |
変数を整数型に制限する 整数以外の値を代入すると 0 扱いになる |
-r |
読み取り専用の変数にする(再代入不可) |
-x |
環境変数としてエクスポートする($ export と同じ) |
-f |
定義された関数を一覧表示する |
-F |
定義された関数名を一覧表示する |
環境変数
親プロセスから子プロセスに引き継がれる変数。
環境変数を介して情報を参照することで、シェルまたはシステム全体で情報を共有することができる。
システム全体で利用する環境変数は、シェル起動時に実行される /etc/bash.bashrc
ファイル(Bash の場合)にて $ export
を実行する。
ユーザ固有の環境変数は ~/.bashrc
にて $ export
する。
ただし、これらの設定ファイル はシェルの起動時にしか読み込まれないため、シェル起動後にファイルを編集した場合は $ source
コマンドによって再読み込みさせる必要がある。
また、スクリプト内でも $ export
を使って環境変数を設定することはできるが、その環境変数はスクリプト内でのみ有効であり、スクリプトが終了すると使用することはできない。つまり、親シェルに環境変数は反映させることができない。
もしスクリプトから呼び出し元のシェル(親プロセス)でも有効な環境変数を設定したい場合、$ source スクリプト
という形で現在のシェル上で実行する必要がある。
$ export
シェル変数を環境変数として設定する。環境変数となった変数は、子プロセスに引き継がれる。
$ export 定義済みシェル変数名
$ export PATH="/some/directory:$PATH"
末尾の :$PATH
は、a = 1 + a
という形で既存の $PATH
を上書きしないようにしている。
シェル変数を定義すると同時に環境変数としても設定することもできる。
$ export 環境変数名=値
設定ファイルに $ echo
とリダイレクト演算子 >>
を利用して追記することもできる。
$ echo 'export PATH="/some/directory:$PATH"' >> ~/.bashrc # Bash
$ echo 'export PATH="/some/directory:$PATH"' >> ~/.zshrc # Zsh
$ export PATH="/some/directory:$PATH"
$ printenv
環境変数の一覧を表示する。
$ printenv
特定の環境変数を指定することもできる。
$ printenv 環境変数名
$ env
環境変数を表示したり、一時的な環境変数を設定しながら別のコマンドを実行する。
単に $ env
とした場合、$ printenv
と同様に環境変数の一覧が表示される。
$ env
下記のように記述すると、現在のシェルプロセスには影響を与えず子プロセス内でのみ有効な環境変数を設定することができる(こちら を参照)。
$ env 環境変数名=値 コマンド
$ env -i コマンド
子プロセスの環境変数を設定する
コマンドを実行する際に、環境変数の宣言をコマンドの前に置くことで、実行されるコマンド(子プロセス)でのみ有効な環境変巣を設定することができる。
現在のシェルプロセスには影響を与えずに環境変数を利用することができる。
$ 環境変数名=値 コマンド
$ env
を利用した場合も同じ。
$ env 環境変数名=値 コマンド
カーネル変数
カーネルの動作を制御するための設定値。
カーネル変数の変更は、動作中のカーネルに対して即時反映される。
$ systemctl
を使用して確認、変更することができる。
また、カーネル変数は /proc/sys/
ディレクトリ配下のファイルを介して、確認、変更することもできる。
$ systemctl -a # すべて表示
$ systemctl 変数名
$ cat /proc/sys/ファイル名
$ systemctl -w カーネル変数名=値
$ echo 値 > /proc/sys/ファイル名
カーネル変数の変更を永続的に行いたい場合、/etc/sysctl.conf
を編集する必要がある。
カーネル変数名 = 値
カーネル変数 | パス | 説明 |
---|---|---|
net.ipv4.ip_forward |
/proc/sys/net/ipv4/ip_forward |
パケットのフォワーディング(ルータ機能の有効化) |
net.ipv4.icmp_echo_ignore_all |
/proc/sys/net/ipv4/icmp_echo_ignore_all |
$ ping への反応を無効化 |
net.ipv4.conf.all.rp_filter |
/proc/sys/net/ipv4/conf/all/rp_filter |
逆方向パケットフィルタの設定(IP スプーフィング対策) |
vm.swappiness |
/proc/sys/vm/swappiness |
スワップ使用の閾値。 低いほど物理メモリが優先される |
fs.file-max |
/proc/sys/fs/file-max |
システム全体の最大オープンファイル数 |
設定ファイル
シェルには Bash や Zsh などの種類ごとに設定ファイルが存在する。
各設定ファイルは スクリプト形式 で記述されており、それぞれ実行されるタイミングが異なる。そのため、実行されるタイミングに合わせて必要な環境設定を行うことができる。
主に以下のような棲み分けになっている。
-
/etc/
- システム全体で共有される設定
-
~/
- ユーザ毎のホームディレクトリ
- ユーザ毎に使用する設定
ログインシェル と 対話型シェル で実行されるファイルが異なる。
/etc/profile
- 対象:ログインシェル
- 読み込まれるタイミング:OS へのログイン時
- 主な用途:システム全体の環境設定
~/.bash_profile
- 対象:ログインシェル
- 読み込まれるタイミング:OS へのログイン時
- 主な用途:ユーザーごとの環境設定
-
Welcome ${whoami}!
のようなログイン時にだけ表示するメッセージなど - ログインシェルにおいても対話型シェルの設定を利用するために、
~/.bash_profile
内でsource ~/.bashrc
するのが一般的
~/.bash_login
- 対象:ログインシェル
- 読み込まれるタイミング:OS へのログイン時
-
~/.bash_profile
が存在しない場合にのみ、実行される
~/.profile
- 対象:ログインシェル
- 読み込まれるタイミング:OS へのログイン時
-
~/.bash_profile
も~/.bash_login
も存在しない場合にのみ、使用される
/etc/bash.bashrc
- 対象:対話型シェル(ログイン・非ログインに関わらず実行される)
- 読み込まれるタイミング:Bash の起動時
- 主な用途:システム全体の対話型シェル設定
- Debian系(Ubuntu、Debian)で利用される
/etc/bashrc
- 対象:対話型シェル
- 読み込まれるタイミング:Bash の起動時
- 主な用途:システム全体の対話型シェル設定
-
~/.bashrc
から呼ばれ、間接的に実行される - Red Hat系(CentOS、Fedora、RHEL)で利用される
~/.bashrc
- 対象:対話型シェル
- 読み込まれるタイミング:Bash の起動時
- 主な用途:ユーザーごとの対話型シェル設定
- エイリアスの設定など
~/.bash_logout
- 対象:ログインシェル
- 読み込まれるタイミング:OS からのログアウト時
- 主な用途:一時ファイルを削除したり、画面をクリアするなど
- 設定ファイルがなければ実行されない
ログインシェル
ログインして最初に起動されるシェル。
ログインシェルには以下がある。
- 仮想コンソール でログインしたとき
- SSH でログインしたとき
$ ssh ユーザー名@ホスト
- 明示的にログインシェルとして Bash などを起動したとき
$ bash --login
-
$ su - ユーザー名
($ su
だけだとログインシェルにならない) - 最初に起動されるシェルではないが、ログインシェルとして振る舞う(以下の設定ファイルの読み込みの挙動がログインシェルの振る舞いである)
ログインシェルでは、起動時は以下の順に 設定ファイル が読み込まれる。
/etc/profile
-
~/.bash_profile
or~/.bash_login
or~/.profile
終了(ログアウト)時は ~/.bash_logout
が読み込まれる。
非ログインシェル
「ログインシェルではないが、対話型シェルであるシェル」を 非ログインシェル と呼ぶ。
非ログインシェルには以下がある。
- ターミナルアプリを開いたとき
- Bash を普通に起動したとき
- ログイン済みの SSH セッションで Bash を再起動した時
非ログインシェルは対話型シェルの一つなので、起動時に 設定ファイル ~/.bashrc
が実行され、その後、プロンプト表示によってインタラクティブなコマンド入力を待つ状態になるものの、ログインシェルではないため ~/.bash_profile
は読み込まれない。
ただし、環境変数は親シェル(ログインシェル)から引き継がれる。
対話型シェル
ユーザーが直接コマンドを入力できるシェルのこと。インタラクティブシェル とも呼ばれる。
大きな特徴として、プロンプトが表示され、ユーザーの入力を待つという点がある。
対話型シェルには以下がある。
- ログインシェルとして Bash を開いたとき
- ログインシェルは基本的に対話型シェル でもある
$ ssh ユーザー名@ホスト
$ su - ユーザー名
- ターミナルアプリを開いたとき
- ログインシェルではないが、対話型シェル である状態
- 明示的に対話型シェルを起動したとき
-
$ bash -i
(i:interactive)
-
対話型シェルでは起動の度に 設定ファイル ~/.bashrc
が実行される。~/.bashrc
内で /etc/bash.bashrc
が呼ばれることが多い。
非対話型シェル
スクリプトを実行するだけのシェルを 非インタラクティブシェル(非対話型シェル) と呼ぶことがある。
非インタラクティブシェルには以下がある。
- スクリプトが実行されるとき
$ bash myscript.sh
- シェルスクリプトが シバン
#!/bin/bash
で実行されたとき -
$ bash -c 'コマンド'
でコマンド実行するとき
非インタラクティブシェルでは ~/.bashrc
は自動では読み込まれない。そのため、スクリプト内でエイリアスや関数を利用したい場合、source ~/.bashrc
を明示的に実行する必要がある。
$ shopt
Shell Options
Bash のオプションを設定するためのビルトインコマンド。
$ shopt
オプション名を引数に渡すと、特定のオプションの状態を確認することができる。
$ shopt オプション名
$ shopt -p # s(set)で表示されたものは有効。u(unset)で表示されたものは無効。
現在のシェルセッションで使用中のシェルがログインシェルであるかどうかは、login_shell
オプションを確認することで確認できる。
$ shopt login_shell
$SHELL
ビルトインシェル変数 $SHELL
には、ユーザーのログイン時に設定されたデフォルトのシェルのパスが格納されている。ただし、現在動作中のシェルとは限らない。
$ echo $SHELL
/bin/zsh
$0
ビルトインシェル変数 の $0
には、現在実行中のシェルまたはスクリプトの名前が格納されている。ログインシェルの場合、先頭に -
が付く。
$ echo $0 # Bash のみ
-zsh
$ source
/ $ .
指定したシェルスクリプトを 現在のシェル環境で 実行する。
$ source スクリプトファイル名
環境設定ファイル を編集した際に、シェルを再起動することなく反映させるために使用される。
$ source ~/.bashrc
$ source
コマンドで読み込んだスクリプトは、現在起動しているシェルのプロセス内で実行されるため、環境変数やエイリアスなどを、起動中のシェル環境に適用させることができる。
ドット $ .
もコマンドであり $ source
と同じ機能を持つ。
$ . スクリプトファイル名
$ source
と $ bash
との違い
$ source スクリプトファイル名
$ source
は呼び出したシェルプロセス内で実行される。
$ bash コマンド名
一方、bash
は呼び出し元のシェルが新しいシェルプロセスを起動し、引数に渡したコマンドは新たに起動したBashのプロセス上で実行される。
そのため、
$ bash ~/.bashrc
としても、設定の変更や変数の宣言は呼び出し元のシェルプロセスには反映されない。
標準入出力 / リダイレクト / パイプ
$ man
manual
コマンドのマニュアルページを表示する。
$ man コマンド名
表示されたマニュアルは Q
キーを押すことで終了する。
$ man
コマンドは、コマンドのマニュアルページだけでなく、設定ファイル、ライブラリ、システムコールなどのマニュアルページも表示させることができる。
$ man 検索ワード
-f
: 完全一致 ($ whatis
コマンドと同じ)
-k
: 部分一致 ($ apropos
コマンドと同じ)
マニュアルページにはセクションと呼ばれる分類があり、セクション番号があらかじめわかっている場合、番号を指定して検索を行うことができる。
$ man セクション番号 検索ワード
セクション | 内容 |
---|---|
1 | ユーザコマンド |
2 | システムコール |
3 | 標準Cライブラリ |
4 | デバイスファイル |
5 | 設定ファイル |
6 | ゲーム |
7 | その他 |
8 | システム管理コマンド |
9 | Linux独自のカーネル用ドキュメント |
ディストリビューションに含まれるパッケージのドキュメントは /usr/share/man/
配下に格納されている。後からダウンロードしたものは /usr/local/share/man/
配下に格納される。
$ exit
現在のシェルプロセスを終了する。スクリプト内で実行した場合、そのスクリプトの実行を即座に終了する。
$ exit
引数に数値を指定することで、終了ステータス を呼び出し元に返却することができる。
シェルからスクリプトを実行した場合には、スクリプトを起動したシェルに終了ステータスが返却され、シェルから別のシェルを起動し、そのシェル内で $ exit
を実行すると、元のシェルに制御が戻り、終了ステータスが返る。
$ exit 終了ステータス
$ exit
コマンドの終了ステータスには、直前のコマンドの $? をそのまま引数として渡すこともできる。
$ exit $?
$ tmux
Terminal Multiplexer
擬似端末 のセッションを管理するターミナルマルチプレクサ。
マルチプレクサ(MUX)は、複数の入力信号の中から1つを選択して出力するデジタル回路や装置のこと。
$ tmux
を利用することで、1つのターミナルアプリ内で複数の擬似端末を管理することができる。
ターミナルのタブ機能やペイン機能に似た操作ができるが、これらはターミナルアプリの GUI による視覚的な管理であるのに対し、$ tmux
は CUI による管理という違いがある。
通常、ターミナルのタブやペインに紐づくプロセスはターミナルを閉じると終了するが、$ tmux
のセッションは tmux
プロセスが動いている限り維持される。
また デタッチ、アタッチ という特徴的な機能がある。
さらに $ ssh
を利用したネットワーク越しの操作において、作業途中で接続が切断された場合でも、tmux
のセッションは端末の外部で動いているので、SSH切断の影響を受けず、サーバー上で動作し続ける。そのため、SSH再接続後に作業を再開させることができる。
$ tmux
コマンドの実行により、新規セッションが作成される。
$ tmux
$ tmux new -s セッション名
tmux
セッション内での操作は主にキー入力によって行うことができる。Ctrl
+ B
を押した後に特定のキーを再び押すという順番になっていて、Ctrl
+ B
を プレフィックスキーと言う。
キー | 説明 |
---|---|
Ctrl + B → C
|
新しいウィンドウを作成(Create) |
Ctrl + B → N
|
次のウィンドウに切り替え(Next) |
Ctrl + B → P
|
前のウィンドウに切り替え(Previous) |
Ctrl + B → &
|
現在のウィンドウを削除 |
Ctrl + B → %
|
垂直にペインを分割 |
Ctrl + B → "
|
水平にペインを分割 |
Ctrl + B → 矢印キー
|
アクティブなペインを切り替え |
Ctrl + B → D
|
デタッチ |
$ tmux attach |
アタッチ |
$ tmux new |
新しいセッションを作成 |
$ tmux new -s セッション名 |
セッション名を指定して新しいセッションを作成 |
$ tmux list-sessions |
セッションを一覧表示 |
$ tmux kill-session |
セッションを終了 |
$ tmux kill-session -t セッション名 |
指定したセッションを終了 |
デタッチ / アタッチ
Detach / Attach
$ tmux
は 擬似端末 との接続を管理する役割を果たす。
(学習メモ:自分のようなLinux初学者には、デタッチやアタッチのイメージが非常に湧きづらかった。「計算装置(サーバ)に接続された 物理的な端末装置(キーボードとディスプレイ)」を頭に思い浮かべると、tmux
のデタッチ・アタッチの動作をイメージしやすいかもしれないと思った。昔は「端末を切り替える」と言ったら、作業者が端末Aから端末Bに移動するしかなかった。)
デタッチ
- 現在のターミナルから
tmux
セッションの接続を切る - (作業者が端末の席から離れる、もしくはディスプレイの電源を切るイメージ。計算装置は稼働し続ける。)
-
tmux
セッション自体はサーバー上で動作し続ける - 現在のターミナルからは操作できなくなる
アタッチ
-
tmux
セッションを開く - (作業者が端末前の席に座る、もしくはディスプレイの電源を入れるイメージ。元々、計算装置は稼働しているぜn)
- ターミナルを通じて
tmux
セッションを操作できる状態になる