こんにちは、InfraAcademyというインフラ学習サービスを運営しているryuです。
今回の記事では、Linuxでよく見かけるshとは何かを、初心者向けにわかりやすく解説します。
Linuxを学習していると、次のような表記を目にします。
sh script.sh
#!/bin/sh
また、ファイル名がbackup.shやsetup.shとなっていることもあります。
「shはシェルスクリプトの略なの?」
「/bin/shはBashと同じもの?」
「.shファイルは、どのシェルで実行されるの?」
最初に結論をまとめると、shは標準的なシェルのコマンド名や、そのシェルで利用するコマンド言語を指す言葉です。歴史的なBourne Shellを起源としていますが、現在のLinuxで/bin/shを実行したときに、必ず当時のBourne Shellが起動するわけではありません。
Ubuntuではdash、環境によってはbashなど、POSIX互換のシェルが/bin/shとして使われます。
shとは?¶
shは、Unix系OSで使用される標準的なコマンド言語インタープリターです。
利用者が入力したコマンドを解釈してプログラムを実行したり、複数のコマンドをまとめたシェルスクリプトを処理したりします。
次のコマンドを実行すると、現在の環境に用意されているshが起動します。
sh
この状態でLinuxコマンドを実行できます。
pwd
ls
echo "Hello"
終了して元のシェルへ戻る場合は、exitを実行します。
exit
ただし、shを単純にshell scriptの略と考えるのは正確ではありません。
.shはシェルスクリプトによく付ける拡張子ですが、コマンドとしてのshは、標準シェルを起動したり、スクリプトを実行したりするための名前です。
そもそもシェルとは?¶
シェルとは、利用者が入力したコマンドを解釈し、OSへ処理を依頼するソフトウェアです。
たとえば、次のコマンドを入力したとします。
ls -l /var/log
シェルは入力された文字列を解析し、lsコマンドへ-lと/var/logを引数として渡して実行します。
シェルには、次のような役割があります。
- 入力されたコマンドを解釈する
- プログラムを実行する
- パイプやリダイレクトを処理する
- 変数を展開する
- 条件分岐や繰り返し処理を実行する
- 複数のコマンドを自動実行する
シェルはLinuxを操作するためのコマンド実行環境であり、簡単なプログラミング言語としての機能も持っています。
shとBourne Shellの関係¶
shの起源となったのが、Bourne Shellです。
Bourne ShellはStephen Bourneによって開発され、初期のUnixで標準シェルとして使われました。変数、条件分岐、繰り返し処理、関数などを利用でき、後の多くのシェルへ影響を与えています。
この歴史から、shをBourne Shellと説明することがあります。
ただし、現在のLinuxで/bin/shを実行しても、歴史的なBourne Shellそのものが起動するとは限りません。
現在のshは、POSIXで定められた標準的なシェルの仕様を利用するための入口として考えると理解しやすくなります。
/bin/shとは?¶
/bin/shは、システム上で標準シェルとして利用するプログラムへのパスです。
多くのLinuxでは、/bin/sh自体が実際のシェルではなく、別のシェルを指すシンボリックリンクになっています。
実体は、次のコマンドで確認できます。
readlink -f /bin/sh
Ubuntuでは、次のように表示されることがあります。
/usr/bin/dash
別の環境では、Bashを指す場合もあります。
/usr/bin/bash
つまり、同じ#!/bin/shと書かれたスクリプトでも、実際に処理するプログラムはOSによって異なる可能性があります。
そのため、/bin/sh向けのスクリプトでは、特定のシェルだけが持つ機能を避け、標準的な書き方を使うことが重要です。
主なシェルの種類¶
LinuxやUnix系OSでは、sh以外にもさまざまなシェルが使われています。
| シェル | 主な特徴 |
|---|---|
| sh | 標準的なシェル。移植性を重視したスクリプトで使われる |
| bash | shとの互換性を持ち、履歴、補完、配列などの機能を追加 |
| dash | 軽量なPOSIX互換シェル。Ubuntuの/bin/shなどで使われる |
| ksh | Bourne Shellを拡張したシェル |
| zsh | 高度な補完やカスタマイズ機能を持つ |
| csh・tcsh | C言語に似た構文を持つ |
普段ターミナルを操作するシェルと、スクリプトを実行するシェルは同じとは限りません。
普段はBashやZshを使っていても、スクリプトの先頭が#!/bin/shなら、そのスクリプトは/bin/shで実行されます。
.sh拡張子とは?¶
backup.shのような.shは、そのファイルがシェルスクリプトであることを人に伝えるためによく使われる拡張子です。
backup.sh
setup.sh
deploy.sh
ただし、Linuxでは拡張子だけで実行方法が決まるわけではありません。
シェルスクリプトは、.shを付けなくても実行できます。
backup
deploy
反対に、ファイル名が.shで終わっていても、どのシェルで実行するかは拡張子だけでは判断できません。
実行するシェルは、次のどちらかで決まります。
sh script.shのように、実行時にシェルを指定する./script.shのように直接実行し、先頭のシバンで指定する
.shは便利な命名規則ですが、シェルの実体を決める設定ではありません。
シバンとは?¶
シェルスクリプトの先頭には、次のような記述があります。
#!/bin/sh
この1行目をシバンと呼びます。
シバンは、そのファイルを直接実行したときに、どのインタープリターで処理するかをOSへ伝えます。
次のスクリプトをhello.shとして保存します。
#!/bin/sh
echo "Hello, sh!"
実行権限を追加します。
chmod +x hello.sh
直接実行します。
./hello.sh
この場合は、シバンに書かれた/bin/shがスクリプトを処理します。
Bash固有の機能を使う場合は、次のように指定します。
#!/bin/bash
実際に使用している構文とシバンを一致させることが重要です。
sh script.shと./script.shの違い¶
次の2つは似ていますが、シェルの決まり方が異なります。
sh script.sh
./script.sh
sh script.shでは、コマンドとして指定したshがファイルを読み込みます。この場合、シバンは実行するシェルの選択には使われません。
一方、./script.shでは、OSがシバンを読み取り、記載されたインタープリターを起動します。
先頭が#!/bin/bashのスクリプトをsh script.shで実行すると、Bashではなくshとして処理されます。Bash固有の構文を使っている場合は、エラーになる可能性があります。
想定どおりに実行する場合は、実行権限を付けて./script.shで実行するか、明示的にbash script.shを使いましょう。
shとbashの違い¶
Bashは、Bourne Again Shellの略です。Bourne Shellとの互換性を意識しながら、多くの便利な機能を追加しています。
| 比較項目 | sh | bash |
|---|---|---|
| 主な目的 | 標準的で移植しやすい処理 | 対話操作や高機能なスクリプト |
| 配列 | 標準的なshでは利用しない | 利用できる |
[[ 条件 ]] |
利用しない | 利用できる |
| ブレース展開 | 利用しない | 利用できる |
| 履歴・補完 | 実装による | 対話操作向けの機能が豊富 |
| 移植性 | POSIXの範囲なら高い | Bashがある環境が必要 |
たとえば、次はBashで利用できる配列です。
#!/bin/bash
servers=("web01" "web02" "db01")
echo "${servers[0]}"
このスクリプトのシバンを#!/bin/shへ変更すると、環境によっては構文エラーになります。
一方、次の書き方は標準的なshで利用できます。
#!/bin/sh
for server in web01 web02 db01
do
echo "$server"
done
shとbashはどちらを選ぶべき?¶
多くのUnix系環境で動かしたいスクリプトでは、#!/bin/shを選び、POSIXに沿った構文で記述する方法があります。
たとえば、次のような用途です。
- インストール処理の補助
- システムの起動・終了処理
- 複数環境へ配布する簡単なスクリプト
- 最低限のシェルしかない環境での実行
Bashが利用できることを前提に、配列や高度な文字列処理を使いたい場合は#!/bin/bashを選びます。
「処理が短いからsh、長いからBash」と決めるのではなく、必要な機能と実行する環境で判断しましょう。
現在使っているシェルを確認する方法¶
ログインシェルは、次のコマンドで確認できます。
echo "$SHELL"
ただし、$SHELLはログイン時に設定されたシェルを表すため、現在実行中のシェルと一致しない場合があります。
現在のプロセスは、次のコマンドで確認できます。
ps -p $$ -o comm=
shの実体を確認する場合は、次のコマンドです。
readlink -f /bin/sh
なお、スクリプト内の$0は、シェル名ではなくスクリプトのファイル名になることがあります。echo $0だけで実装を断定しないようにしましょう。
shの基本的なスクリプトを作ってみよう¶
標準的な構文を使った簡単なスクリプトを作成します。
vi check-user.sh
次の内容を入力します。
#!/bin/sh
user_name=$(whoami)
if [ "$user_name" = "root" ]; then
echo "rootユーザーで実行されています"
else
echo "現在のユーザー: $user_name"
fi
実行権限を追加して実行します。
chmod +x check-user.sh
./check-user.sh
変数を参照するときは、次のようにダブルクォートで囲む習慣を付けましょう。
"$user_name"
空白や特殊文字を含む値でも、意図しない単語分割を防ぎやすくなります。
shやシェルスクリプトを実践しながら学ぶ¶
shやBashは、説明を読むだけでは身につきにくい分野です。
InfraAcademyのLinux入門講座では、Linuxコマンド、ファイル操作、権限、プロセス、シェル、シェルスクリプトなどを、ブラウザ上のLinux環境で実際に操作しながら学習できます。
Linuxサーバーが通信する仕組みも理解したい方は、ネットワーク入門講座もおすすめです。
また、シェルスクリプトを使ってEC2の設定やAWS上の作業を効率化したい方は、AWS講座へ進むと、Linuxの知識をクラウド環境へつなげられます。
shとは?まとめ¶
今回は、shの意味と、/bin/sh、.sh、Bashとの違いについて解説しました。
- shは、標準的なシェルのコマンド名やコマンド言語を指す
- shの起源はBourne Shellだが、現在の
/bin/shが必ずBourne Shellとは限らない /bin/shは、Ubuntuではdashなど別のシェルを指すことがある.shはシェルスクリプトであることを示す慣習的な拡張子- 直接実行するときは、先頭のシバンがインタープリターを決める
sh script.shでは、指定したshがファイルを処理する- 移植性を重視するなら標準的なshの構文を使う
- Bash固有の機能が必要なら、
#!/bin/bashを指定する
まずはreadlink -f /bin/shを実行し、自分のLinux環境で/bin/shがどのシェルを指しているのか確認してみましょう。



