4 使用例
GNU grepを起動するコマンドの例を示します。
grep -i 'hello.*world' menu.h main.c
これは、ファイルmenu.hとmain.cから、文字列「hello」の後ろに文字列「world」が現れるすべての行を一覧表示します。「.*」が行内の0文字以上に一致するためです。「正規表現」を参照してください。-iを指定すると、grepは大文字と小文字を区別しなくなるため、指定しない場合は一致しない行「Hello, world!」にも一致します。
次は、現在のディレクトリーで、名前が「.」以外で始まり、「g」を含み、「.h」で終わるすべてのファイルから、「f」を含み「.c」で終わる行の位置と内容を表示する、より複雑な例です。-nは行番号を出力します。引数--は、*g*.hが「-」で始まるファイル名に展開されても、後続の引数をオプションではなくファイル名として扱わせます。空のファイル/dev/nullを加えることで、「*g*.h」の形のファイル名が偶然1つしかなくても、ファイル名を出力します。
grep -n -- 'f.*\.c$' *g*.h /dev/null
パターンで使う正規表現の構文は、シェルがファイル名の照合に使うグロブの構文と異なります。
grepの起動方法について詳しくは、「grepの起動」を参照してください。
以下に、grepの使用に関するよくある質問と回答を示します。
- 一致するファイルの名前だけを一覧表示するには?
grep -l 'main' test-*.c
これは、現在のディレクトリーにある「test-*.c」ファイルのうち、内容に「main」を含むファイルの名前を一覧表示します。
- ディレクトリーを再帰的に検索するには?
grep -r 'hello' /home/gigi
これは、/home/gigiディレクトリー以下のすべてのファイルから「hello」を検索します。検索するファイルを細かく制御するには、
findとgrepを使います。たとえば、次のコマンドはCファイルだけを検索します。find /home/gigi -name '*.c' ! -type d \ -exec grep -H 'hello' '{}' +これは、次のコマンドとは異なります。
grep -H 'hello' /home/gigi/*.c
こちらは、/home/gigiにある、名前が「.c」で終わる隠しファイル以外のCファイルから「hello」を検索するだけです。上の
findコマンドラインは、次のコマンドにより近いものです。grep -r --include='*.c' 'hello' /home/gigi
- パターンやファイル名が「-」で始まる場合は?たとえば、
grep "$pattern" *
これは、「pattern」の値が「-」で始まる場合や、「*」が「-」で始まるファイル名に展開される場合、予期しない動作になることがあります。避けるには、パターンに-eを使い、ファイル名の先頭に「./」を付けられます。
grep -e "$pattern" ./*
これは、作業ディレクトリーにある、名前が「.」で始まらないすべてのファイルから、パターンに一致するすべての行を検索します。-eがない場合、
grepは「-」で始まるパターンをオプションとして扱う場合があります。「./」がない場合、「-」で始まるファイル名にも同様の問題が生じることがあります。または、パターンとファイル名の前に「--」を指定できます。
grep -- "$pattern" *
これも問題を解決しますが、「-」という名前のファイルがあると、
grepは「-」を標準入力として誤解釈します。 - 単語の一部分ではなく、単語全体を検索するには?
grep -w 'hello' test*.log
これは、単語全体である「hello」だけを検索し、「Othello」には一致しません。より細かく制御するには、単語の先頭と末尾に一致する「\<」と「\>」を使います。たとえば、
grep 'hello\>' test*.log
これは、「hello」で終わる単語だけを検索するため、単語「Othello」にも一致します。
- 一致行の前後の文脈を出力するには?
grep -C 2 'hello' test*.log
これは、各一致行の前後に2行の文脈を表示します。
grepに必ずファイル名を表示させるには?/dev/nullを追加します。
grep 'eli' /etc/passwd /dev/null
次の出力が得られます。
/etc/passwd:eli:x:2098:1000:Eli Smith:/home/eli:/bin/bash
または、GNU拡張の-Hを使います。
grep -H 'eli' /etc/passwd
psの出力に変わった正規表現を使うのはなぜ?ps -ef | grep '[c]ron'
パターンを角括弧なしで書くと、
cronについてのpsの出力行だけでなく、grepについてのpsの出力行にも一致します。一部のプラットフォームでは、psが出力を画面幅に制限することに注意してください。grepの行長の制限は、利用可能なメモリーだけです。grepが「binary file matches」と表示するのはなぜ?grepがバイナリーファイルの一致する「行」をすべて一覧表示すると、役に立たない出力になる可能性が高く、画面表示を乱す場合さえあります。そのため、GNUgrepは、バイナリーと思われるファイルの出力を抑制します。バイナリーと思われるファイルからも行を出力させるには、GNUgrepで-aまたは「--binary-files=text」を使います。「Binary file matches」メッセージを出さないようにするには、-Iまたは「--binary-files=without-match」を使います。- 「grep -lv」が一致しないファイル名を表示しないのはなぜ?
「grep -lv」は、一致しない行を1行以上含むすべてのファイルの名前を一覧表示します。一致行をまったく含まないすべてのファイルの名前を一覧表示するには、-Lまたは--files-without-matchを使います。
- 「|」でORはできますが、ANDは?
grep 'paul' /etc/motd | grep 'franc,ois'
これは、「paul」と「franc,ois」の両方を含むすべての行を探します。
- 空のパターンがすべての入力行に一致するのはなぜ?
grepコマンドは、パターンに一致する文字列を含む行を検索します。すべての行が空の文字列を含むため、空のパターンではgrepが各行で一致を見つけます。このようなパターンはほかにもあり、「^」、「$」など、多くのパターンでgrepはすべての行に一致します。空行に一致させるには、パターン「^$」を使います。空白だけの行に一致させるには、パターン「^[[:blank:]]*$」を使います。どの行にも一致させないためには、「a^」や「$a」のような拡張正規表現を使います。すべての行に一致させるため、移植可能なスクリプトでは、空のパターンの代わりに「^」のようなパターンを使うべきです。POSIXは空のパターンの動作を規定していません。
- 標準入力とファイルの両方を検索するには?
特殊なファイル名「-」を使います。
cat /etc/passwd | grep 'alain' - /etc/motd
- シェルの「set -e」と
grepを組み合わせられないのはなぜ?grepコマンドは、cmpやdiffのようなプログラムと同様、終了状態1をエラーとしない慣例に従います。シェルコマンド「set -e」は、いずれかのサブコマンドが0以外の状態で終了するとシェルを終了させます。このため、grepが行を選択しなかっただけでシェルが終了し、通常は望んだ結果になりません。Bashの
set -e -o pipefailにも関連する問題があります。grepは常に入力をすべて読むとは限りません。grepが読むパイプに出力するコマンドは、grepが全入力を読み終える前に終了すると失敗する場合があり、そのコマンドの失敗によってBashが終了することがあります。 - この後方参照が失敗するのはなぜ?
echo 'ba' | grep -E '(a)\1|b\1'
2つ目の「\1」には参照先がなく、何にも一致しないため、これはエラーメッセージを出力します。
- 行をまたいで一致させるには?
標準的なgrepは本質的に行単位で動作するため、これを行えません。そのため、文字クラス
[:space:]を使うだけでは、期待したようには改行に一致しません。GNU
grepの-z(--null-data)を使うと、入力と出力の各「行」はNUL文字で終わります(「その他のオプション」を参照)。このため入力の改行に一致させられますが、通常は一致があると入力全体を出力します。そのため、-qのような出力を抑制するオプションと組み合わせることがよくあります。たとえば、printf 'foo\nbar\n' | grep -z -q 'foo[[:space:]]\+bar'
これで足りない場合は、
grepに渡す前に入力を変換したり、awk、sed、perlなど、行をまたいで処理するためのユーティリティーを使ったりできます。 grep、-E、-Fは何の略?grepという名前は、Unixで行の編集を行っていた方法に由来します。たとえば、edは、一致行の一覧を画面へ表示するため、次の構文を使います。global/regular expression/print g/re/p
-EはExtended
grep(拡張grep)の略です。-FはFixedgrep(固定grep)の略です。egrepとfgrepはどうなった?第7版Unixには、現在の「grep -E」と「grep -F」に相当する
egrepとfgrepコマンドがありました。1970年代の小さなコンピューターでは、grepを3つのプログラムに分けることが役立ったかもしれませんが、egrepとfgrepは1992年にPOSIXで廃止予定とされ、2001年にPOSIXから削除されました。GNU Grep 2.5.3では2007年に非推奨となり、GNU Grep 3.8では2022年に廃止予定の警告を表示するようになりました。将来的には完全に削除する予定です。古い名前を使いたい場合は、独自の代用品を使えます。たとえば、
egrepという名前で次の内容のシェルスクリプトを作れます。#!/bin/sh exec grep -E "$@"