シェルの環境

INPUT · スライド

引用符で守る(`'` と `"` と `\`)

01 / 06

2種類の引用符

引用符が2種類あるのを不思議に思ったことはないかな。ちゃんと違いがあるんだ。

~ $ echo 'a $HOME'a $HOME~ $ echo "a $HOME"a /home/manabiya

同じものを囲んだのに、結果が違ったね。

囲み方シェルの振る舞い
'...'(シングル)何も書きかえない。見たままを渡す
"..."(ダブル)$ は書きかえる。空白は守る
囲まない$* も書きかえ、空白で区切る

覚え方はこうだよ。

シングル = 完全に守る(強い)ダブル   = 空白だけ守る(ふつう)無し     = 何も守らない(弱い)

この章のはじめから言っている視点が、ここでも効くよ。書きかえているのはシェルなんだ。引用符は、そのシェルに向けた「触らないで」という合図だね。

そして引用符はコマンドには届かないよ。囲みの記号自体は、シェルが取り除いてから渡すんだ。

02 / 06

空白は区切りだった

引用符がいちばん必要になるのは、空白のせいだよ。

~ $ lsaru fairu.txt~ $ ls aru fairu.txtls: aru: No such file or directoryls: fairu.txt: No such file or directory

1つのファイル名なのに、2つの相手として扱われたね。

ls aru fairu.txt   ↑    ↑  1つめ  2つめ(空白で区切られた)

シェルは空白を見たら「ここで区切り」と考えるんだ。だから空白を含む名前は、囲んで守らないといけないよ。

~ $ ls "aru fairu.txt"aru fairu.txt

1文字だけ守る方法もあるよ。

~ $ ls aru\ fairu.txt

\ は「次の1文字を、特別な意味なしに扱う」という印だよ。バックスラッシュと呼ぶね。

これで章1からの疑問が解けるでしょう。

> なぜファイル名に空白を入れないほうがよいと言われるのか

毎回囲まないといけないからだよ。囲み忘れると、まったく違う動きになってしまうんだ。

03 / 06

* を誰が広げているか

これも驚くところだよ。

~ $ echo *memo1.txt memo2.txt~ $ echo '*'*

echo* を広げていないんだ。

echo *  ↓ シェルが先にファイル名に広げるecho memo1.txt memo2.txt

コマンドが受け取る時点で、もう広がっているんだよ。だから ls *.txt* を解釈しているのも ls ではなくシェルだね。

これを知らないと、こういう罠にはまるよ。

~ $ find . -name *.txtfind: unrecognized: memo2.txt

シェルが先に *.txtmemo1.txt memo2.txt に広げてしまい、find には意味の分からない引数が届いたんだ。

正しくはこうだよ。

~ $ find . -name "*.txt"./memo1.txt./memo2.txt

囲んでfind 自身に判断させるんだね。find は自分で * を解釈できるからだよ。

ls *.txt        シェルに広げてもらう(これでよい)find -name "*.txt"  find に広げてもらう(囲む)

誰に仕事をさせたいのかで、囲むかどうかが決まるんだ。

04 / 06

ダブルの中の $ を止める

ダブルクォートの中でも $ を止めたいときがあるよ。そのときは \ を使うんだ。

~ $ echo "kingaku: \$100"kingaku: $100

\$ で「これはただのドル記号」と伝えているんだね。囲みの中でも \ は効くんだ。

ダブルの中でダブルを使いたいときも同じだよ。

~ $ echo "kakko \"naka\" owari"kakko "naka" owari

シングルの中はちょっと厄介だよ。シングルの中では \ も効かないからね。

~ $ echo 'it\'s'      ← これは動かない

いったん閉じて、外で守って、また開けるという手を使うんだ。

~ $ echo 'it'\''s'it's

分けて読むとこうだよ。

'it'     シングルで囲んだ it\'       外で守った ''s'      シングルで囲んだ s

3つがくっついて it's になるんだ。隣り合った引用符はつながるという決まりだね。

もっと簡単な逃げ道もあるよ。

~ $ echo "it's"it's

ダブルの中ならシングルはただの文字だからね。ぶつからない引用符を選ぶのがいちばん楽なんだ。

05 / 06

変数は必ず囲む

この章でいちばん実用的な作法を言うよ。

> 変数を使うときは "$名前" と囲む

理由を見てみよう。

~ $ F="aru fairu.txt"~ $ rm $Frm: can't remove 'aru': No such file or directoryrm: can't remove 'fairu.txt': No such file or directory

変数を置きかえたあとに、シェルがもう一度空白で区切ったんだ。

rm $F  ↓ 置きかえるrm aru fairu.txt  ↓ 空白で区切る相手が2つになった

囲めば起きないよ。

~ $ rm "$F"

これは実務で本当に事故になるところだよ。

DIR="/home/user/my documents"rm -r $DIR        ← /home/user/my と documents を消そうとする

もし /home/user/my が実在したら、消えてしまうんだ。

だから合言葉はこれだよ。

迷ったら "$変数" と囲む

囲んで困ることは、ほとんど無いからね。空白が無い値なら結果は同じで、あるときだけ助かるんだ。

06 / 06

さあ、打ってみよう

この回で使う形をまとめておくね。

echo '$HOME'          そのまま渡す(何も書きかえない)echo "$HOME"          中身に置きかえるecho \$HOME           1文字だけ守るecho "\$100"          ダブルの中で $ を止めるecho 'it'\''s'         シングルの中にシングルを入れるls "aru fairu.txt"    空白を含む名前を渡すrm "$F"               変数は囲むfind . -name "*.txt"  * を find 自身に渡す

確かめ方のコツをひとつ。echo で先に見てみるんだ。

~ $ echo rm $F        本当に打つ前に、何が渡るか見るrm aru fairu.txt      ← あ、2つになっている!

消す前に確かめられるでしょう。rmmv のような取り消せない操作の前に、echo を付けて打ってみる。これはプロも使う手だよ。

最後に、判断の順番を1つの形にまとめておくね。

1. 中身を展開したい?    → はい: ダブル / いいえ: シングル2. 空白が入るかも?      → はい: どちらかで囲む3. 記号を守りたいだけ?  → \ を1文字に付ける

これだけで、引用符の悩みはほとんど解けるよ。では打ってみよう。