変数とクオート
変数は name="値" の形で代入します。= の前後にスペースを入れない点が要注意です。値を取り出すときは $name または ${name} と書きます。文字列をダブルクオート "..." で囲むと中の変数は展開され、シングルクオート '...' で囲むと展開されずそのままの文字になります。空白や特殊文字を含む値は、意図しない分割を防ぐため "$name" のように常にダブルクオートで囲むのが安全です。
変数は、値に名前を付けて入れておく入れ物だ。ある値を後の行でもう一度使いたいとき、その値に名前を付けておけば何度でも呼び出せる。
ファイル名・回数・ユーザからの入力など、後で何度も使う値を変数にしておくと、一か所を直すだけで全体に反映でき、読みやすさも保守のしやすさも上がる。
bash の変数はとても手軽に使え、あらかじめ「これは数値」「これは文字列」と型を宣言する必要はない。基本的にすべて文字列として扱われ、必要に応じて数値としても解釈される、というゆるやかな仕組みになっている。
🚫 = の前後に空白を入れない
変数への代入は 名前=値 と書く。ここで最初の関門が現れる。= の前後に空白を入れてはいけないのだ。
たとえば name="太郎" は正しい代入だが、name = "太郎" のように空白を挟むと、bash は name をコマンド名だと誤解してしまい、name: コマンドが見つかりません といったエラーになる。
理由はこうだ。bash にとって、空白で区切られた先頭の語はコマンド名だ。だから空白を入れた瞬間、name は変数ではなく実行すべきコマンドに見えてしまう。
これは初学者が非常によくつまずく落とし穴なので、「代入のイコールは前後をくっつけて書く」と体で覚えてほしい。
値に空白を含めたいときは name="山田 太郎" のようにクオートで囲む。複数の単語からなる値を裸で書くと、空白のところで切れて意図しない代入になってしまう。
💲 取り出すときは $ を付ける
代入した値を取り出す(参照する)ときは、変数名の前に $ を付けて $name と書く。echo "$name さん、こんにちは" のように使うと、$name の部分が代入された値に置き換わって表示される。
ここで一つ厄介な場面がある。変数名のすぐ後ろに文字を続けたいときだ。そんなときは波カッコ付きの ${name} を使う。
たとえば ${name}san と書けば「name という変数の値に san を足したもの」と解釈される。だが波カッコ無しで $namesan と書くと、bash は namesan という別の変数名だと受け取ってしまい、空の値に化けてしまう。どこまでが変数名なのか、bash には区別がつかないからだ。
「どこまでが変数名か」をはっきりさせたいときは ${...} を使う、と覚えておくと安全だ。${name}_bak のようにアンダースコアを挟む場合も同様に波カッコが効く。
✂ クオートは2種類あって中身の扱いが違う
文字列を囲むクオートには2種類あり、中の変数の扱い方が決定的に違う。変数を中身に変えたいときと、書いたままの文字として見せたいときの両方があるからだ。
ダブルクオート "..." は、中に書いた $変数 を値に置き換えて(変数展開して)から処理する。
一方シングルクオート '...' は、中身をいっさい解釈せず、書いたままの文字として扱う。つまり $ すら特別な意味を失い、ただの文字になる。
具体例で見ると違いがはっきりする。$ 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" と囲んでおけば、全体が1つの値として正しく扱われ、こうした事故を防げる。
空になり得る変数を条件式などで裸のまま使うと式そのものが壊れることもある。「変数参照は基本的にダブルクオートで囲む」を初期設定の習慣にしておくと、後々のトラブルを大きく減らせる。この囲む癖は、次の条件分岐の章でもう一度効いてくる。
🌐 このシェル限りの変数か、子にも伝える変数か
変数には、そのシェルの中だけで通用する普通の変数と、そこから起動した子プロセス(別のコマンドやスクリプト)にも引き継がれる環境変数の区別がある。
区別が要るのは、自分のシェルでしか使わない値まで子プロセスに全部渡すと、かえって混乱するからだ。
普通の変数を環境変数に格上げするには export を使い、export NAME=値 あるいは既存の変数に対して export NAME と書く。代表的な環境変数には、コマンドの探索先を並べた PATH や、ホームディレクトリを指す HOME がある。
たとえば自分の変数をスクリプトの中の別コマンドにも渡したいときは export しておく必要があり、export せずに定義した変数は呼び出した先のプロセスからは見えない。
「このシェル限りで使うなら普通の変数、呼び出す先にも伝えたいなら export」と押さえておくと、設定が思ったとおりに伝わらないときの切り分けに役立つ。
⌨ 入力を受け取る read と、つまずきの三点
利用者にキーボードから値を打ち込んでもらい、それを変数に受け取りたいときは read コマンドを使う。read name と書くと、その行で入力された文字が変数 name に入る。
質問文を一緒に出したいときは read -p "お名前は? " name のように -p で促し文を付けると、表示と入力を1行にまとめられる。echo と組み合わせて echo -n "続けますか? "(-n は改行しない指定)のように促してから read する書き方もよく見かける。
最後に、変数まわりでつまずきやすい点を整理しておく。第一に、代入の = の前後に空白を入れてしまう誤り。第二に、参照のときに $ を付け忘れて変数名をそのまま文字として出してしまう誤り。第三に、空白を含む値を "$var" と囲まずに使って単語に分割されてしまう誤り。
この3つが代表的なつまずきどころで、変数が思った値にならないときは、まずここを疑うと早く原因にたどり着ける。