質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

MacOS(OSX)

MacOSとは、Appleの開発していたGUI(グラフィカルユーザーインターフェース)を採用したオペレーションシステム(OS)です。Macintoshと共に、市場に出てGUIの普及に大きく貢献しました。

Q&A

解決済

2回答

1090閲覧

grepの引数として$記号を渡す際のエスケープについて

applepine

総合スコア6

bash

bash(Bourne-again-Shell)は sh(Bourne Shell)のインプリメンテーションに様々な機能が追加されたシェルです。LinuxやMac OS XではBashはデフォルトで導入されています。

MacOS(OSX)

MacOSとは、Appleの開発していたGUI(グラフィカルユーザーインターフェース)を採用したオペレーションシステム(OS)です。Macintoshと共に、市場に出てGUIの普及に大きく貢献しました。

0グッド

0クリップ

投稿2019/09/15 08:26

編集2019/09/15 14:29

bashで正規表現の検索パターンとして$記号を指定したいのですが、エスケープが必要ということは理解しているのですがエスケープはバックスラッシュを直前に1つ入れると理解しているのですが、この場合$ではうまくいかず$のようにバックスラッシュを2つ差し込むとうまく動くのですがなぜ1つではダメなのでしょうか?

macOS

1export GREP_OPTIONS='--color=always' 2echo I love $ | grep \$ 3I love $ 4echo I love $ | grep $ 5I love $ 6

上記のコードでは表現しづらいでが、手元のbashではバックスラッシュを2ついれると$記号が赤字で出力されるのですが、1つだと黒字で出力されています。

初歩的な質問で申し訳ありませんが、回答よろしくお願いします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

applepine

2019/09/16 01:59 編集

失礼しました。 以後他のサービス共に方針を踏まえて気をつけます。
guest

回答2

0

ベストアンサー

  1. $はbashでは環境変数の展開に使われる
  2. $の後の文字が空白文字だったり行末だったりで展開することがなければ$のままになる
  3. bashで$の変数展開をやめさせければ\でクォートする
  4. bashで\によるクォートをやめさせたければ\とする
  5. 正規表現で$行末に長さ0でマッチする
  6. '$'という文字にマッチさせる正規表現は$

plain

1export GREP_OPTIONS='--color=always' 2C=love

環境変数Cをセットしておきましょう。

plain

1echo I love C$C | grep $C

の結果は
I love Clove
です。(強調表示部分がカラー表示です。以下同様)

$Cが文字列ioveに展開されているのが分かりますね。echo I love Clove | grep loveを実行したのと同じことなのです。

質問で

plain

1echo I love $

するとI love $が出るのは"$の後続がアルファベットじゃないから環境変数として正しくない"ため$自身がでています。


環境変数の展開を明示的に止めたい時はどうするかというと、\でエスケープします。

plain

1echo I love C$S | grep $

とすると結果は
I love C$S
です。強調表示がありません。
にも関わらずI love C$Sが表示されていることに気をつけてください。(echo hoge | grep hugaでは結果が出ないことを確認してください)
ということはこの行はマッチしているのです。
$ が行末にマッチする正規表現なので、行末に長さ0でマッチしているのです。
だからマッチしていてかつ強調表示がないという結果になるのです。


plain

1echo I love C$C | grep e$

すると結果は
I love Clove
です。
e$ が "eの直後に行末" という意味になるので行末のeにしかマッチしていないことを確認してください。

plain

1echo I love C$C | grep e

の結果が
I love Clove
なのと見比べてください。


正規表現で$という文字自身を検索したい時は$という正規表現を渡さなければなりません。

bashで$と書くと\記号の作用で変数展開をやめて$という文字自身になります。
\は渡りません。
\を渡したければ\と書きます。

plain

1echo $C

の結果が
$C
で($の変数展開する機能が\で抑止されている)

plain

1echo \$C

の結果が
\love
で(\の「$の変数展開を抑止する機能」がもう1つの\で抑止されている。$は変数展開の機能を持つ)

plain

1echo \$C

の結果が
$C
なことを確認してください。
(\の「$の変数展開を抑止する機能」がもう1つの\で抑止されている。$の変数展開する機能が\で抑止されている)


以上から質問でやりたいことをキッチリ書くなら

plain

1echo I love $ | grep \$

とします。
こうするとechoはI love $という文字列を出力して、grepは第1引数に$を取ります。

これで文字列中の$にマッチして
I love $
という結果を得ます。

投稿2019/09/15 13:56

編集2019/09/15 15:26
quickquip

総合スコア11029

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

applepine

2019/09/16 03:11

回答ありがとうございます。 様々な例をあげながら結果を比較しながら説明していただき、非常にわかりやすく理解することができました。助かりました。 またマルチポストに関してご指摘いただいたことを踏まえて、利用規約に注意してサービスを利用させていただきます。ご迷惑、お手数をおかけして申し訳ありません。
guest

0

Bashが、引数の\$$にしてそれをgrepに渡します。

シェルの特殊文字(空白文字、| > < & など)自体をプログラムに渡したいときは、バックスラッシュを前置するか引用符で囲みます。

例:1つの空白をコマンドに渡したい場合

sh

1grep \ 2grep ' ' 3grep " "

$自体もシェルの特殊文字なので、\$と書かないといけないケースもあります。
例:$Aをプログラムに渡したい場合

sh

1grep \$A ⇒ NG ($Aが変数展開される) 2grep \$A ⇒ OK

投稿2019/09/15 09:01

otn

総合スコア84423

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

applepine

2019/09/15 09:45

回答ありがとうございます! >Bashが、引数の\$を$にしてそれをgrepに渡します。 よろしければこの部分についてもう少し説明していただけないでしょうか? ネットで調べても特殊記号を通常の文字として扱うにはバックスラッシュを直前に1つつけるとの記載しか見つからないのですが、もう一つのバックスラッシュはどういった意味合いがあるのでしょうか?何かをエスケープしているのでしょうか? また、特殊記号のエスケープにはバックスラッシュが2ついるということなのでしょうか? 1つの場合と、2ついる場合があるのであればその違いについて処理の仕組みから理解したいのですがよろしければ教えていただけないでしょうか? よろしくお願いします。
otn

2019/09/15 10:26

1つ目の\が2つめの\をエスケープして、通常であればシェルの特殊文字である\を単なるバックスラッシュという文字としてあつかい、それをプログラムに渡します。 それが、 >Bashが、引数の\$を$にしてそれをgrepに渡します。 という意味です。 > また、特殊記号のエスケープにはバックスラッシュが2ついるということなのでしょうか? いいえ。 > 特殊記号を通常の文字として扱うにはバックスラッシュを直前に1つつける は正しいです。 シェルで、\や$を特殊文字として扱わないために、それぞれ\を1つ必要とします。 grepが$を末尾を示す特殊文字として扱わないために、\を1つ必要とします。 どちらも\を1つずづたけ必要としています。 もう一度書きますが、grepに渡す必要があるのは $ で、それぞれシェルの特殊文字なので、それぞれの前に1つずつ \ をつけて、\$ にします。 このシェルコマンド grep \$ を出力するCのプログラムを書くと、Cの文字列の中に\を書くには、\ と\を1つ付ける必要があるので、 printf("grep \\\$\n"); というプログラムになります。
applepine

2019/09/15 11:04

丁寧に説明していただきありがとうございます。 度々質問して申し訳ないのですが、 >Bashが、引数の\$を$にしてそれをgrepに渡します >もう一度書きますが、grepに渡す必要があるのは $ で、それぞれシェルの特殊文字なので、それぞれの前に1つずつ \ をつけて、\$ にします。 \も$もそれぞれ特殊記号でありそれをgrepに渡す際に\が一つずつ必要というのはわかったのですが、ではなぜ\$でも意図通り出力することが可能なのでしょうか?$の前に\がもう一ついるのではないでしょうか? >このシェルコマンド grep \$ を出力するCのプログラムを書くと、Cの文字列の中に\を書くには、\ と\を1つ付ける必要があるので、 printf("grep \\\$\n"); というプログラムになります。 すいません、こちらもどこに\と\をつけたのかお示ししていただけないでしょうか? 初心者なもので理解が乏しくお手数をおかけして恐縮です。 よろしくお願いします。
otn

2019/09/15 15:14 編集

> なぜ\$でも意図通り出力することが可能なのでしょうか?$の前に\がもう一ついるのではないでしょうか? $は変数展開を行う特殊文字ですが、$の次の文字が変数展開につかう文字ではない(この場合は行末とか空白とか)なので、$は変数展開に使われずそのままです。 例: echo \$ ⇒ $ が出力される echo \$ ⇒ $ が出力される echo \$HOME ⇒ \の後に変数HOMEが展開されて出力される echo \$HOME ⇒ $HOME という文字列が出力される つまり$の次の文字によって、\ が必要だったり不要だったりします。なので常につけることにしたほうがいいです。 > すいません、こちらもどこに\と\をつけたのかお示ししていただけないでしょうか? 3つある\のそれぞれの前に1つの\をつけます。\をつけるのは一度には必ず1つずつですよ。
applepine

2019/09/16 03:05

例を用いてわかりやすく説明していただき、理解することができました。 ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問