🐧 Linux 総合学習プラットフォーム
シェルスクリプト ・ 入門

変数とクオート

変数は name="値" の形で代入します。= の前後にスペースを入れない点が要注意です。値を取り出すときは $name または ${name} と書きます。文字列をダブルクオート "..." で囲むと中の変数は展開され、シングルクオート '...' で囲むと展開されずそのままの文字になります。空白や特殊文字を含む値は、意図しない分割を防ぐため "$name" のように常にダブルクオートで囲むのが安全です。

変数は、値に名前を付けて入れておく入れ物だ。ある値を後の行でもう一度使いたいとき、その値に名前を付けておけば何度でも呼び出せる。

ファイル名・回数・ユーザからの入力など、後で何度も使う値を変数にしておくと、一か所を直すだけで全体に反映でき、読みやすさも保守のしやすさも上がる。

🔗
たとえ変数は名前を貼った箱。中に値を入れておけば、後から名前を呼ぶだけで何度でも取り出せる。

bash の変数はとても手軽に使え、あらかじめ「これは数値」「これは文字列」と型を宣言する必要はない。基本的にすべて文字列として扱われ、必要に応じて数値としても解釈される、というゆるやかな仕組みになっている。

代入(しまう)name='太郎'name太郎$ を付けて取り出す参照(取り出す)$name → 太郎

🚫 = の前後に空白を入れない

変数への代入は 名前=値 と書く。ここで最初の関門が現れる。= の前後に空白を入れてはいけないのだ。

たとえば name="太郎" は正しい代入だが、name = "太郎" のように空白を挟むと、bash は name をコマンド名だと誤解してしまい、name: コマンドが見つかりません といったエラーになる。

つまずき代入の = は前後をくっつける。name="太郎" は正しく、name = "太郎" だと name がコマンド扱いになり失敗する。

理由はこうだ。bash にとって、空白で区切られた先頭の語はコマンド名だ。だから空白を入れた瞬間、name は変数ではなく実行すべきコマンドに見えてしまう。

これは初学者が非常によくつまずく落とし穴なので、「代入のイコールは前後をくっつけて書く」と体で覚えてほしい。

値に空白を含めたいときは name="山田 太郎" のようにクオートで囲む。複数の単語からなる値を裸で書くと、空白のところで切れて意図しない代入になってしまう。

💲 取り出すときは $ を付ける

代入した値を取り出す(参照する)ときは、変数名の前に $ を付けて $name と書く。echo "$name さん、こんにちは" のように使うと、$name の部分が代入された値に置き換わって表示される。

echo "$name さん、こんにちは" ……$name が代入された値に置き換わって表示される。取り出すときは $ を忘れない。

ここで一つ厄介な場面がある。変数名のすぐ後ろに文字を続けたいときだ。そんなときは波カッコ付きの ${name} を使う。

たとえば ${name}san と書けば「name という変数の値に san を足したもの」と解釈される。だが波カッコ無しで $namesan と書くと、bash は namesan という別の変数名だと受け取ってしまい、空の値に化けてしまう。どこまでが変数名なのか、bash には区別がつかないからだ。

コツ変数のすぐ後ろに文字を続けるなら ${name}san のように波カッコで囲む。どこまでが変数名かをはっきり示せる。

「どこまでが変数名か」をはっきりさせたいときは ${...} を使う、と覚えておくと安全だ。${name}_bak のようにアンダースコアを挟む場合も同様に波カッコが効く。

✂ クオートは2種類あって中身の扱いが違う

文字列を囲むクオートには2種類あり、中の変数の扱い方が決定的に違う。変数を中身に変えたいときと、書いたままの文字として見せたいときの両方があるからだ。

ダブルクオート "..." は、中に書いた $変数 を値に置き換えて(変数展開して)から処理する。

一方シングルクオート '...' は、中身をいっさい解釈せず、書いたままの文字として扱う。つまり $ すら特別な意味を失い、ただの文字になる。

name='太郎' のときダブルクオート(展開する)echo "$name さん"→ 太郎 さんシングルクオート(そのまま)echo '$name さん'→ $name さん

具体例で見ると違いがはっきりする。$ name="太郎" としたうえで、echo "$name さん" は「太郎 さん」と表示するが、echo '$name さん' は「$name さん」とそのまま表示する。

💡
ポイント変数を展開したいならダブルクオート、$ や記号をそのまま文字として見せたいならシングルクオート。

「変数の中身を使いたいときはダブルクオート、記号や $ をそのまま文字として見せたいときはシングルクオート」という対比で理解すると整理できる。

スクリプトの中で固定の文字列を出すだけならシングルクオート、値を埋め込みたいならダブルクオート、という使い分けが基本だ。

🛡 変数は "$name" と囲むのが安全

変数を参照するときは、できるだけ "$name" のようにダブルクオートで囲むのが安全な書き方だ。

値に空白や特殊文字が含まれていると、囲まずに裸で $name と書いた場合にシェルがその空白で値を複数の単語に分割してしまうからだ。

たとえば file="my report.txt" という変数を裸で rm $file と渡すと、シェルはこれを rm my report.txt と解釈し、my と report.txt という2つの別物を消そうとしてしまう。狙ったのは1つのファイルなのに、だ。

つまずきfile="my report.txt" を裸で rm $file と渡すと、my と report.txt の2つと誤解される。"$file" と囲めば防げる。

"$file" と囲んでおけば、全体が1つの値として正しく扱われ、こうした事故を防げる。

空になり得る変数を条件式などで裸のまま使うと式そのものが壊れることもある。「変数参照は基本的にダブルクオートで囲む」を初期設定の習慣にしておくと、後々のトラブルを大きく減らせる。この囲む癖は、次の条件分岐の章でもう一度効いてくる。

🌐 このシェル限りの変数か、子にも伝える変数か

変数には、そのシェルの中だけで通用する普通の変数と、そこから起動した子プロセス(別のコマンドやスクリプト)にも引き継がれる環境変数の区別がある。

区別が要るのは、自分のシェルでしか使わない値まで子プロセスに全部渡すと、かえって混乱するからだ。

親シェルNAME普通の変数export環境変数子プロセスexport した変数だけ届く

普通の変数を環境変数に格上げするには export を使い、export NAME=値 あるいは既存の変数に対して export NAME と書く。代表的な環境変数には、コマンドの探索先を並べた PATH や、ホームディレクトリを指す HOME がある。

export NAME=値 ……普通の変数を環境変数に格上げする。export すれば、呼び出した子プロセスからもその値が見える。

たとえば自分の変数をスクリプトの中の別コマンドにも渡したいときは export しておく必要があり、export せずに定義した変数は呼び出した先のプロセスからは見えない。

「このシェル限りで使うなら普通の変数、呼び出す先にも伝えたいなら export」と押さえておくと、設定が思ったとおりに伝わらないときの切り分けに役立つ。

⌨ 入力を受け取る read と、つまずきの三点

利用者にキーボードから値を打ち込んでもらい、それを変数に受け取りたいときは read コマンドを使う。read name と書くと、その行で入力された文字が変数 name に入る。

read -p "お名前は? " name ……-p で促し文を出しつつ入力を受け取り、変数 name に入れる。表示と入力を1行にまとめられる。

質問文を一緒に出したいときは read -p "お名前は? " name のように -p で促し文を付けると、表示と入力を1行にまとめられる。echo と組み合わせて echo -n "続けますか? "(-n は改行しない指定)のように促してから read する書き方もよく見かける。

最後に、変数まわりでつまずきやすい点を整理しておく。第一に、代入の = の前後に空白を入れてしまう誤り。第二に、参照のときに $ を付け忘れて変数名をそのまま文字として出してしまう誤り。第三に、空白を含む値を "$var" と囲まずに使って単語に分割されてしまう誤り。

つまずき変数が思った値にならないときの三大原因は、= の前後の空白・$ の付け忘れ・クオート漏れ。まずここを疑う。

この3つが代表的なつまずきどころで、変数が思った値にならないときは、まずここを疑うと早く原因にたどり着ける。

この項目に出てくる用語

変数へんすう
値に名前を付けて保存する入れ物。name=値 で代入し $name で参照。
クオートくおーと
文字列を引用符で囲み、空白や特殊文字の解釈を制御すること。
環境変数かんきょうへんすう
export で子プロセスにも引き継がれるようにした変数。

関連コマンド

echoexportread

▶ 学習アプリでこの続きを学ぶ・演習する