ドル記号($
)
通常grep
でメタ文字を検索するときにはバックスラッシュ(\
)(または円マーク)
を付けてエスケープする必要がありますが、
この際にシェルのエスケープ/変換も効くのでシェルで変換されるものに関しては
注意が必要です(他のシェルでも大概同じだと思いますがbashでの環境を前提にしてます)。
ドル記号($)は変数の参照に使うので、エスケープせずに 単純にこれを書くと続く文字列の変数を 参照する様な形になって、大概の場合は未定義変数=空文字で 全ての行が該当してしまいます1。
$ printf "aaa\nbbb\$ccc" |grep "$ccc"
aaa
bbb$ccc
これをきちんと$ccc
で検索するにはドル記号をエスケープして
$ printf "aaa\nbbb\$ccc" |grep "\$ccc"
bbb$ccc
とするか、シングルクォートで囲むことで囲み内を展開しない様に
$ printf "aaa\nbbb\$ccc" |grep '$ccc'
bbb$ccc
とすればOK2。
$ printf "aaa\nbbb\$ccc" |grep '\$ccc'
bbb$ccc
の様にバックスラッシュをを付けておいても(多分)grep
での展開時に\$
が外れるので
$ccc
で検索されます。
ただ、ドル記号単独の場合がちょっと特殊で、
$ printf "aaa\nbbb\$ccc" |grep "\$"
aaa
bbb$ccc
の様に単なる空文字として認識されてる様子。
ただ、bashでは$
単独ではそのままの文字として認識されるのと、
$ printf "aaa\nbbb\$ccc" |grep \$
aaa
bbb$ccc
の様にダブルクォートを外しても同じ結果でエラーが出ないのでちょっと特殊。
上の$ccc
の場合だと、ダブルクォートを外すと
未定義で何も無いのと同じなので、grep
を引数なしで実行しようとしてエラーが出ます。
なので空の文字""
として認識されている様子。
このドル記号単独を検索したい場合は
$ printf "aaa\nbbb\$ccc" |grep "\\$"
bbb$ccc
の様にバックスラッシュを2つ付ける(ダブルクォートなしでも大丈夫) か
$ printf "aaa\nbbb\$ccc" |grep '\$'
bbb$ccc
シングルクォートで囲ってかつバックスラッシュでエスケープすると出来ます。
上の場合は恐らくシェル的に最初のバックスラッシュ二つの部分が、
前のバックスラッシュが後者をエスケープする形で一つ残り、
grep
的に\$
を$
だと理解してるんだと思います。
後者はそのまま\$
がgrep
に渡されて最終的に$
として理解される感じ。
バックスラッシュ(\
)
バックスラッシュを検索したい場合は
$ printf "aaa\nbbb\\ccc" |grep "\\\\"
bbb\ccc
と四つのバックスラッシュを使う(ダブルクォートで囲むか何も囲まない)か
シングルクォートで囲って二つのバックスラッシュ
$ printf "aaa\nbbb\\ccc" |grep '\\'
bbb\ccc
にすると出来ます。
これも前者の場合はまずシェルがバックスラッシュ二つ続きを一つに変換するので
結果的に後者と同じくバックスラッシュ二つになって、
これがgrep
に渡されて前のバックスラッシュがエスケープになり
後ろのバックスラッシュが最終的に渡される感じかと。
これ以外だと、ダブルクォートの中にバックスラッシュ一つだと
$ printf "aaa\nbbb\\ccc" |grep "\"
>
となります。二つ目のバックスラッシュがエスケープされるので ダブルクォートが閉じてないので入力が続いてる状態。
ダブルクォートにバックスラッシュ二つだと、
$ printf "aaa\nbbb\\ccc" |grep "\\"
grep: trailing backslash (\)
の様に、grep
に渡されるのがバックスラッシュ一つになってgrep
が困惑してしまいます。
これはシングルクォート内にバックスラッシュ一つ書いても同じ。
まとめ
- ドル記号の検索:
grep "\\$"
またはgrep '\$'
- バックスラッシュの検索:
grep "\\\\"
またはgrep '\\'