LoginSignup
8
6

More than 5 years have passed since last update.

シェルのダブルクォートとバッククォートのエスケープの展開

Posted at

やりたかったこと

Bash on Windowsで、プロンプト(user@hostname:~$のやつ)のホスト名の部分を変更したかったのですが、どうもWindows側でマシン名を変えないといけないっぽい。
それは面倒なので、$PS1をいじって、ホスト名を変えずにプロンプトの表示だけ変えてみます。
元の$PS1はこんな感じ

$ echo $PS1
\[\e]0;\u@\h: \w\a\]${debian_chroot:+($debian_chroot)}\u@\h:\w\$

この\hの部分がホスト名になるので、sedで置換すればいいだろう、ということで以下のようにしてみました。PCがLet's Noteなので、ホスト名はLET'S_NOTEで。

$ export PS1=`echo $PS1 | sed "s/\\h/LET'S_NOTE/g"`
$ echo $PS1 
\[\e]0;\u@\LET'S_NOTE: \w\a\]${debian_cLET'S_NOTEroot:+($debian_cLET'S_NOTEroot)}\u@\LET'S_NOTE:\w\$

はい、見事に失敗です。どうも\\hのエスケープが上手くいっていないっぽいです。
というわけで、バックスラッシュを増やしてみたところ、上手くいきました。

$ echo `echo $PS1 | sed "s/\\\\\h/LET'S_NOTE/g"`
\[\e]0;\u@LET'S_NOTE: \w\a\]${debian_chroot:+($debian_chroot)}\u@LET'S_NOTE:\w\$
$ echo `echo $PS1 | sed "s/\\\\\\\\\\\\h/LET'S_NOTE/g"`
\[\e]0;\u@LET'S_NOTE: \w\a\]${debian_chroot:+($debian_chroot)}\u@LET'S_NOTE:\w\$

試してみたところ、バックスラッシュ5個〜12個なら上手く行くようです。
でも5個でも12個でも同じ結果って、一体どういう展開がされているのか気になったので、いろいろ試してみました。

シェルのエスケープの展開

""と``

まず、""の展開の仕方を見てみます。

$ echo "\h"
\h
$ echo "\\h"
\h
$ echo "\\\h"
\\h
$ echo "\\\\h"
\\h

次にコマンド展開の``。シングルクォートの文字列は展開されないので、それをechoしてコマンド置換してみます。

$ echo '\\h'
\\h
$ echo `echo '\h'`
\h
$ echo `echo '\\h'`
\h
$ echo `echo '\\\h'`
\\h
$ echo `echo '\\\\h'`
\\h

つまり、どちらも\\\に変換し、\hはそのまま残しているようです。

sedの正規表現のエスケープ展開

次にsedです。

$ echo 'hoge\h' | sed 's/\h/fuga/g'
fugaoge\fuga
$ echo 'hoge\h' | sed 's/\\h/fuga/g'
hogefuga
$ echo 'hoge\h' | sed 's/\\\h/fuga/g'
hogefuga
$ echo 'hoge\h' | sed 's/\\\\h/fuga/g'
hoge\h

こちらはダブルクォートの文字列やコマンド展開とは違い、\hhに変換しているようです。
正規表現だから当たり前といえば当たり前かもしれません。

結果

この結果をもとに先ほどのケースを考えてみると納得できそうです。
以下は、わかりやすいように適宜スペースを入れています。

  • バックスラッシュ4個の場合
    • バッククォートの展開:\\ \\ hが展開され、\ \ h
    • ダブルクォートの展開:\\ hが展開され、\ h
    • 正規表現の展開:\hが展開され、h
  • バックスラッシュ5個の場合
    • バッククォートの展開:\\ \\ \hが展開され、\ \ \h
    • ダブルクォートの展開:\\ \hが展開され、\ \h
    • 正規表現の展開:\\ hが展開され、\ h
  • バックスラッシュ12個の場合
    • バッククォートの展開:\\ \\ \\ \\ \\ \\ hが展開され、\ \ \ \ \ \ h
    • ダブルクォートの展開:\\ \\ \\ hが展開され、\ \ \h
    • 正規表現の展開:\\ \hが展開され、\ h

同様に考えると、6〜11個のときも説明できそうです。

文字列と正規表現の展開のされ方が微妙に違っていることを意識するいい機会になりました。

8
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
6