やってみる

アウトプットすべく己を導くためのブログ。その試行錯誤すらたれ流す。

シェルとコマンドラインシェルとシェルスクリプトの違い

 混乱するので用語の確認をしてみた。

違い

用語 意味
シェル コマンドラインインタプリタ。ユーザがOSを操作するためのインタフェース。
コマンドラインシェル Unixシェルのこと。コマンドをパイプでつなげたジョブを記述する。俗にシェル芸、ワンライナーと呼ばれる。
シェルスクリプト OSシェルまたはコマンドラインインタプリタ向けに書かれたスクリプト言語である。

コマンドラインシェルとシェルスクリプトの違い

 改行。コマンドラインシェルは1行にせねばならない。そのために{}, (), ;, && を使う。シェルスクリプトは文を改行で区切れる。

呼び方

 「シェル」と言ったとき「シェル」か「コマンドラインシェル」か「シェルスクリプト」か不明瞭。会話では文脈で判断することになる。略すときの方針を以下に仮定してみた。

用語
シェル シェル
コマンドラインシェル シェル
シェルスクリプト スクリプト

 シェルとコマンドラインシェルの区別をつける場面は少ないと思われる。伝わらなかったら「インタフェース、インタプリタのほう」「コマンドラインシェルのほう、ターミナルに打つヤツ」と言って区別してはどうか。シェルスクリプトについては「ファイルに書くヤツ、シバンを書くヤツ」などと言えば伝わりそう。頭悪そう。

シェル芸とは

 非公式な用語。日本固有と思われる。

マウスも使わず、ソースコードも残さず、GUIツールを立ち上げる間もなく、あらゆる調査・計算・テキスト処理をCLI端末へのコマンド入力一撃で終わらすこと。あるいはそのときのコマンド入力のこと。

 コマンドラインシェルを使って何らかの意味ある仕事をさせること、だと思う。

コマンドラインシェル

 たとえば以下のようなコード。

echo -e 'A\nB\nA\nC' | sort | uniq > distinct.txt
echo -e 'A\nB\nC' | grep 'B' > result.txt

 \を行末に付与すれば複数行に渡って表記できる。(改行コードのエスケープ)

echo -e 'A\nB\nC' \
| grep 'B' \
> result.txt

 関数の定義と実行もできる。

Func() { echo -e 'A\nB\nC' | grep 'B' > result.txt; }; Func

 ただし改行コードを途中に含めることはできない。文の区切りを改行にすると実行できない。

> Func() { \
>  local INPUT=$(echo -e 'A\nB\nC') \
>  echo "$INPUT" | grep 'B' > result.txt \
> } \
> Func;
bash: 予期しないトークン `;' 周辺に構文エラーがあります

 ;を使って複数文を1行で書けば実行できる。

Func() { local INPUT=$(echo -e 'A\nB\nC'); echo "$INPUT" | grep 'B' > result.txt; }; Func

 なお、;&&にしても良い。

Func() { local INPUT=$(echo -e 'A\nB\nC') && echo "$INPUT" | grep 'B' > result.txt; }; Func

 改行エスケープを使うと以下。(文の終端を;で表し、\で改行エスケープする)

Func() { \
    local INPUT=$(echo -e 'A\nB\nC'); \
    echo "$INPUT" | grep 'B' > result.txt; \
}; \
Func;

シェルスクリプト

 一行目にはshebang (シバン)を書く。

file.sh

#!/bin/bash
echo -e 'A\nB\nC' | grep 'B' > result.txt
#!/bin/bash
Func() { echo -e 'A\nB\nC' | grep 'B' > result.txt; }; Func

 複数の文を連続して実行できる。(行末に; \不要)

#!/bin/bash
Func() {
    local INPUT=$(echo -e 'A\nB\nC')
    echo "$INPUT" | grep 'B' > result.txt
}
Func

 ;で文の終わりを示す。続けて次の文を書ける。これで一行にできる。

#!/bin/bash
Func() {
    local INPUT=$(echo -e 'A\nB\nC'); echo "$INPUT" | grep 'B' > result.txt
}
Func

 ;を使い関数定義も一行に。

#!/bin/bash
Func() { local INPUT=$(echo -e 'A\nB\nC'); echo "$INPUT" | grep 'B' > result.txt; }
Func

 ;を使い関数の定義と実行も一行に。

#!/bin/bash
Func() { local INPUT=$(echo -e 'A\nB\nC'); echo "$INPUT" | grep 'B' > result.txt; }; Func

 ここまでくるとシェバンを除いた箇所をコマンドラインシェルとして実行できる。

 set -Ceuすると予期せぬ悲劇を防げるかもしれない。

#!/bin/bash
set -Ceu
Func() { local INPUT=$(echo -e 'A\nB\nC'); echo "$INPUT" | grep 'B' > result.txt; }; Func
フラグ 説明
-C >|としないとリダイレクト時に上書き防止エラーとなる
-e エラー発生時に中断する
-u 存在しない変数を参照するとエラーになり終了する