Linuxでシェルスクリプトのgrepのやり方がよくわかりません。オプションや正規表現を使用した文字列抽出を行いたいです。
そういった声が多いので今回はシェルスクリプトのgrepについて教えます!
現役エンジニアの筆者もよく使用するので、実例などを用いて教示します。
windowsのプロンプトで使用できるbatやpythonやphpを使用して、業務効率化やWebサイトを作成しております。javaやシェルスクリプトなど、様々なプログラミングを行った実績ありの筆者です。
shellscriptのgrepを使用して文字列を抽出する方法はよく使います。シェルスクリプトを使用するなら必須の項目です。
・・・・・シェルスクリプトでgrepの使い方の基本
シェルスクリプトでgrepの使い方の基本
シェルスクリプトでのgrepは検索したい文字列を、指定したファイルから行全体を抽出します。
またデフォルトでは基本正規表現を使用するので、拡張正規表現を使用したい場合はオプションをつけます。
grepの使い方の基本
シェルスクリプトでgrepの使い方の基本構文は以下です。
grep 検索文字列 検索ファイル(パス付き)
検索ファイルについては複数指定できます。半角スペースを区切りにしてファイルを指定していきます。
grep 検索文字列 検索ファイル1 検索ファイル2 . . .
実践:grepの基本
では実際にgrepを使用して文字列を抽出してみます。
grep root /etc/passwd
「root」という文字列を「/etc/passwd」のファイルから抽出しています。
このシェルスクリプトを実行してみます。
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
「/etc/passwd」のファイルで「root」が含まれる行全体が2行抽出されました。
今度は検索するファイルを複数にしてみます。
grep root /etc/passwd /etc/group
「root」という文字列を「/etc/passwd」と「/etc/group」のファイルから抽出しています。
このシェルスクリプトを実行してみます。
/etc/passwd:root:x:0:0:root:/root:/bin/bash
/etc/passwd:operator:x:11:0:operator:/root:/sbin/nologin
/etc/group:root:x:0:
「/etc/passwd」と「/etc/group」で「root」が含まれる行全体がファイル名付きで抽出されました。
grepの検索オプションについて
シェルスクリプトでgrepのオプションについて
grepの検索オプションについてまとめます。
オプション | 効果 |
---|---|
-E | 拡張正規表現を使用 |
-F | 正規表現を使用しない |
-i | 大文字小文字を区別しない |
-e | 検索文字列を指定する |
-v | 検索結果を反転させる |
拡張正規表現を使用したい時につけるのが「-E」オプションです。
シェルスクリプトの基本でデフォルトは基本正規表現を使用すると説明しました。拡張正規表現を使用したい時につけるのが「-E」オプションです。
正規表現を使用したくない場合には「-F」オプションを使用します。
検索文字列の大文字小文字を区別したくない場合は「-i」オプションを使用します。
echo オプションなし
grep Root /etc/passwd
echo オプションあり
grep -i Root /etc/passwd
-iオプションを使用する時としない時のシェルスクリプトを実行してみます。
オプションなし
オプションあり
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
オプションなしの場合Rootの大文字小文字が区別される為、何も表示されません。逆にオプションありの場合はrootが含まれる行が表示されました。
検索文字列を指定する場合は「-e」オプションを使います。主に検索文字列を複数指定したい場合に使用します。
まずエラーが出るシェルスクリプトを実行してみます。
grep root postfix /etc/passwd
例えば複数の文字列を含むものを抽出したい時に、上のシェルスクリプトを実行してみます。
grep: postfix: そのようなファイルやディレクトリはありません
/etc/passwd:root:x:0:0:root:/root:/bin/bash
/etc/passwd:operator:x:11:0:operator:/root:/sbin/nologin
上のような実行結果となりエラーが出ました。
エラーの原因として「root」を含む文字列を「postfix」と「/etc/passwd」のファイルから抽出するシェルスクリプトと認識されているからです。
「postfix」というファイルがないとみなされエラーが出てきます。「/etc/passwd」には「root」があるので表示されています。
エラーの解決法として-eオプションがあります。「postfix」は検索文字列と明示的に指定できます。
grep -e root -e postfix /etc/passwd
このシェルスクリプトのように検索文字列ごとに「-e」オプションを使います。
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
「/etc/passwd」ファイルの中の「root」と「postfix」の文字列が含まれる行が表示されました。
指定した文字列が抽出されて、エラーが出ていないので成功です。
指定した結果を反転させるには「-v」オプションを使用します。
「/etc/passwd」から「root」がない行を表示させるシェルスクリプトです。
grep -v root /etc/passwd | head -n 5
「/etc/passwd」から「root」がない行は多いので5行だけ表示しています。
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
「/etc/passwd」から「root」がない行の先頭5行だけ表示されました。
grepの出力オプションについて
シェルスクリプトでgrepの出力オプションについて
grepの出力に関するオプションについてまとめます。
出力オプション | 出力効果 |
---|---|
-n | 抽出された行番号を表示 |
-H | 抽出されたファイルのファイル名も表示する |
-h | 抽出されたファイルのファイル名は表示しない |
-l | 抽出されたファイルのファイル名のみ表示する |
-L | 抽出されていないファイル名のみ表示する |
-o | 抽出された箇所のみ表示する |
-q | 抽出された箇所を表示しない |
抽出された行番号を表示したい場合は「-n」オプションを使用します。
抽出した文字列がファイルの何行目にあるかを表示したい事はよくあります。
grep -n root /etc/passwd
「/etc/passwd」から「root」がある行を行番号付きで表示します。
1:root:x:0:0:root:/root:/bin/bash
10:operator:x:11:0:operator:/root:/sbin/nologin
1行目と10行目に「root」がある事がわかります。
抽出されたファイルのファイル名も表示する場合は「-H」オプションを使用します。
抽出されたファイルのファイル名も表示したい場合です。
grep -H root /etc/passwd
「/etc/passwd」から「root」がある行をファイル名付きで表示します。
/etc/passwd:root:x:0:0:root:/root:/bin/bash
/etc/passwd:operator:x:11:0:operator:/root:/sbin/nologin
「root」があるファイル名「/etc/passwd」付で行が表示されました。
抽出されたファイルのファイル名は表示しない場合は「-h」オプションを使用します。
抽出されたファイルのファイル名は表示しない場合です。
grep -h root /etc/passwd /etc/group
複数のファイルを指定すればファイル名が表示されますが、不要な場合に使用します。
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
root:x:0:
ファイル名が表示されていない事がわかります。
抽出されたファイルのファイル名のみ表示する場合は「-l」オプションを使用します。
抽出されたファイルのファイル名のみ表示するしたい場合があります。
grep -l root /etc/passwd /etc/group
「-l」オプションを使用します。
/etc/passwd
/etc/group
ファイル名のみ表示されている事がわかります。
抽出されていないファイル名のみ表示する場合は「-L」オプションを使用します。
抽出されていないファイル名のみ表示する場合です。
grep -L root /etc/passwd /etc/group /etc/nsswitch.conf
指定した3ファイルの中で「root」が一つもないファイル名を表示するシェルスクリプトです。
/etc/nsswitch.conf
「root」が一つもないファイル名のみ表示されている事がわかります。
抽出された箇所のみ表示する場合は「-o」オプションを使用します。
抽出された箇所のみ表示する場合です。
echo '複数ファイルの場合'
grep -o root /etc/passwd /etc/group
echo '単体ファイルの場合'
grep -o root /etc/passwd
複数ファイルの場合と単体ファイルの場合で表示してみます。
複数ファイルの場合
/etc/passwd:root
/etc/passwd:root
/etc/passwd:root
/etc/passwd:root
/etc/group:root
単体ファイルの場合
root
root
root
root
ファイルの中に「root」がある数だけ表示されている事がわかります。
抽出された箇所を表示しない場合は「-q」オプションを使用します。
抽出された箇所を表示しない場合です。
grep -q root /etc/passwd /etc/group
指定したファイルの中に「root」があってもなくても表示しないシェルスクリプトです。
実行しても特になにも表示されません。文字列が存在する時としない時の違いは終了ステータスの違いです。
文字列が1つでも存在すれば終了ステータスは「正常」、しなければ「異常」となります。
grepで正規表現を使用する
シェルスクリプトでgrepの正規表現
grepでの正規表現についてまとめます。正規表現には基本正規表現と拡張正規表現があります。
基本的には拡張正規表現を使用していれば問題ありません。
正規表現で文字列を指定する特別な文字をメタ文字と言います。メタ文字がキーとなります。メタ文字とその効果をまとめます。
- 文字を指定するメタ文字
- 繰り返しを意味するメタ文字
- 補助的メタ文字
基本正規表現メタ文字 | 拡張正規表現メタ文字 | 効果 |
---|---|---|
. | . | 何かしらの1文字 |
^ | ^ | 最初の文字 |
$ | $ | 最後の文字 |
[] | [] | 限定文字指定 |
[^] | [^] | 限定文字以外 |
何かしらの文字列を抽出する場合は「.」を使用します。
何かしらの文字列を抽出する場合です。
grep 'roo.' /etc/passwd
指定したファイルの中に「roo」と何らかの1文字の文字列があれば抽出します。
「’」で文字列を囲わなくても抽出できますが、エラーになる指定の仕方もあるので、全て「’」で囲う事を推奨します。
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
「roo」と何らかの文字の「t」が結合された「root」が抽出されました。
最初の文字列を指定するには「^」を使用します。
最初の文字列を指定する場合です。
grep '^root' /etc/passwd
指定したファイルの中で「root」から始まる行を抽出します。
root:x:0:0:root:/root:/bin/bash
「root」から始まる行のみが抽出されました。
最後の文字を指定するには「$」を使用します。
最後の文字を指定する場合です。
grep 'nologin$' /etc/passwd | head -n 3
指定したファイルの中で「nologin」で終わる行を抽出します。
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
「nologin」で終わる行のみが抽出されました。
限定文字を指定するには[]を使用します。
限定文字を指定する場合です。
grep 'roo[stu]' /etc/passwd
指定したファイルの中で「roo」とあと「s」か「t」か「u」かで組み合わせる文字列があれば抽出します。
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
「root」が含まれる行が抽出されました。
grep 'roo[s-u]' /etc/passwd
続き文字列であれば上のように指定もできます。数字であれば[1-3]のようにも指定できます。
限定文字以外を指定するには[^]を使用します。
限定文字以外を指定する場合です。
grep 'roo[^abc]' /etc/passwd
指定したファイルの中で「roo」とあと「a」か「b」か「c」以外の文字で組み合わせる文字列があれば抽出します。
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
「root」が含まれる行が抽出されました。
基本正規表現メタ文字 | 拡張正規表現メタ文字 | 効果 |
---|---|---|
* | * | 直前の文字の0回以上の繰り返し |
無し | + | 直前の文字の1回以上の繰り返し |
無し | ? | 直前の文字の0回もしくは1回の繰り返し |
\{m\} | {m} | 直前の文字のm回の繰り返し |
\{m,\} | {m,} | 直前の文字のm回以上の繰り返し |
\{m,n\} | {m,n} | 直前の文字のm回以上n回以下の繰り返し |
直前の文字の0回以上の繰り返しするには「*」を使用します。
直前の文字の0回以上の繰り返しする場合です。拡張正規表現の場合は「-E」オプションを使用します。
echo 基本正規表現
grep 'roo*t' /etc/passwd
echo 拡張正規表現
grep -E 'roo*t' /etc/passwd
指定したファイルの中で「ro」とその後に「o」の0回以上の繰り返しがあり、その後に「t」が来る文字列を抽出します。「rot」や「root」や「rooot」などが抽出されます。
基本正規表現
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
拡張正規表現
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
どちらも「root」が含まれる行が抽出されました。
直前の文字の1回以上の繰り返しするには「+」を使用します。
直前の文字の1回以上の繰り返しする場合です。拡張正規表現のみ使用できます。
echo 基本正規表現
grep 'roo+t' /etc/passwd
echo 拡張正規表現
grep -E 'roo+t' /etc/passwd
指定したファイルの中で「ro」とその後に「o」の1回以上の繰り返しがあり、その後に「t」が来る文字列を抽出します。「root」や「rooot」などが抽出されます。今回「rot」などは非対象ですね。
基本正規表現
拡張正規表現
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
基本正規表現は対応していないので抽出されず、拡張の方は「root」が含まれる行が抽出されました。
直前の文字の0回もしくは1回の繰り返しするには「?」を使用します。
直前の文字の0回もしくは1回の繰り返しする場合です。拡張正規表現のみ使用できます。
echo 基本正規表現
grep 'ro?t' /etc/passwd
echo 拡張正規表現1
grep -E 'ro?t' /etc/passwd
echo 拡張正規表現2
grep -E 'roo?t' /etc/passwd
echo 拡張正規表現3
grep -E 'rooo?t' /etc/passwd
指定したファイルの中で「r」、「ro」、「roo」とその後に「o」の0回か1回の繰り返しがあり、その後に「t」が来る文字列を抽出しまみます。
基本正規表現
拡張正規表現1
rtkit:x:172:172:RealtimeKit:/proc:/sbin/nologin
拡張正規表現2
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
拡張正規表現3
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
拡張1は「rt」と「rot」、拡張2は「rot」と「root」、拡張3は「root」と「rooot」が抽出されます。
基本正規表現は対応していないので抽出されず、拡張1は「rt」が拡張2と3は「root」が含まれる行が抽出されました。
直前の文字のm回の繰り返しするには{m}を使用します。
直前の文字の繰り返し回数を指定する場合です。基本正規表現を使用したい場合は「{」や「}」の前に「\」を付けます。
echo 基本正規表現
grep 'ro\{2\}t' /etc/passwd
echo 拡張正規表現
grep -E 'ro{2}t' /etc/passwd
指定したファイルの中で「ro」とその後に「o」の2回のみの繰り返しがあり、その後に「t」が来る文字列を抽出します。「root」が抽出されます。「rooot」や「roooot」などは非対象ですね。
基本正規表現
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
拡張正規表現
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
どちらも「root」が含まれる行が抽出されました。
直前の文字のm回以上の繰り返しするには{m,}を使用します。
直前の文字の繰り返し回数以上を指定する場合です。基本正規表現を使用したい場合は「{」や「}」の前に「\」を付けます。
echo 基本正規表現
grep 'ro\{2,\}t' /etc/passwd
echo 拡張正規表現
grep -E 'ro{2,}t' /etc/passwd
指定したファイルの中で「ro」とその後に「o」の2回以上の繰り返しがあり、その後に「t」が来る文字列を抽出します。「root」や「rooot」や「roooot」などが抽出されます。
基本正規表現
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
拡張正規表現
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
どちらも「root」が含まれる行が抽出されました。
直前の文字のm回以上n回以下の繰り返しするには{m,n}を使用します。
直前の文字の繰り返し回数以上と以下を指定する場合です。基本正規表現を使用したい場合は「{」や「}」の前に「\」を付けます。
echo 基本正規表現
grep 'ro\{2,3\}t' /etc/passwd
echo 拡張正規表現
grep -E 'ro{2,3}t' /etc/passwd
指定したファイルの中で「ro」とその後に「o」の2回以上3回以下の繰り返しがあり、その後に「t」が来る文字列を抽出します。「root」や「rooot」が抽出されます。「roooot」などは対象外ですね。
基本正規表現
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
拡張正規表現
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
どちらも「root」が含まれる行が抽出されました。
文字列指定の補助的なメタ文字をまとめます。
基本正規表現メタ文字 | 拡張正規表現メタ文字 | 効果 |
---|---|---|
\ | \ | 直後のメタ文字を普通の文字として扱う |
\(\) | () | 指定する文字列をクループ化する |
無し | | | 複数の正規表現をORで繋げる |
補助的なメタ文字を試すにあたり環境を説明します。シェルスクリプトと同階層に「5_grep」というディレクトリがあり、その配下に「grep_test.txt」があるとします。
「grep_test.txt」の内容は以下とします。
ro\{2\}t
root
abcc
abcbc
abcbcbc
123
12323
1232323
123123123
12333
abcabcabc
直後のメタ文字を普通の文字として扱うには「\」を使用します。
直後のメタ文字を普通の文字として扱う場合です。基本正規表現と拡張正規表現とどちらも使用できます。
echo 基本正規表現1 繰り返し
grep 'ro\{2\}t' 5_grep/grep_test.txt
echo 基本正規表現2 直後のメタ文字を普通の文字として扱う
grep 'ro\\{2\\}t' 5_grep/grep_test.txt
echo 拡張正規表現1 繰り返し
grep -E 'ro\{2\}t' 5_grep/grep_test.txt
echo 拡張正規表現2 直後のメタ文字を普通の文字として扱う
grep -E 'ro\\{2\\}t' 5_grep/grep_test.txt
指定したファイルの中で「ro\{2\}t」という文字列を抽出したいです。しかし「ro\{2\}t」は繰り返しで出てきたoを2回繰り返すメタ文字です。
このままでは「root」が抽出されるので「\」を「\」で普通の文字列にエスケープします。これで「ro\{2\}t」という文字列が抽出できます。
拡張正規表現においては「ro\{2\}t」の「\」はメタ文字と解釈されているので何も表示されません。
同じく「ro\{2\}t」の「\」を「\」で普通の文字列にエスケープします。これで拡張正規表現の方も「ro\{2\}t」という文字列が抽出できます。
基本正規表現1
root
基本正規表現2
ro\{2\}t
拡張正規表現1
拡張正規表現2
ro\{2\}t
どちらも「ro\\{2\\}t」とすることで「ro\{2\}t」という文字列が抽出されました。
指定する文字列をクループ化して扱うには()を使用します。
指定する文字列をクループ化して扱う場合です。基本正規表現と拡張正規表現とどちらも使用できます。
echo 基本正規表現1 単体文字繰り返し
grep 'abc\{2\}' 5_grep/grep_test.txt
echo 基本正規表現2 グループで繰り返し
grep 'a\(bc\)\{2\}' 5_grep/grep_test.txt
echo 拡張正規表現1 単体文字繰り返し
grep -E 'abc{2}' 5_grep/grep_test.txt
echo 拡張正規表現2 グループで繰り返し
grep -E 'a(bc){2}' 5_grep/grep_test.txt
基本正規表現1は指定したファイルの中で「abc」の一つ前の「c」を2回繰り返すというシェルスクリプトでした。しかし「bc」の繰り返しにしたい場合は、基本正規表現2のように該当文字列を\(\)で囲いグループ化します。
拡張正規表現1も同様です。「bc」の繰り返しにしたい場合は、拡張正規表現2のように該当文字列を()で囲いグループ化します。
基本正規表現1
abcc
基本正規表現2
abcbc
abcbcbc
拡張正規表現1
abcc
拡張正規表現2
abcbc
abcbcbc
どちらも「a」とその後に「bc」が2回以上繰り返す文字列が抽出されました。
複数の正規表現をORで繋げるには「|」を使用します。
複数の正規表現をORで繋げる場合です。拡張正規表現しか対応していません。
指定したファイルの中で「abc」か「123」という文字列を抽出したいです。
echo 拡張正規表現1
grep -E 'abc|123' 5_grep/grep_test.txt
「abc|123」で可能です。シェルスクリプトを実行します。
abcc
abcbc
abcbcbc
123
12323
1232323
123123123
12333
abcabcabc
指定したファイルの中で「abc」か「123」という文字列を含む行が抽出されました。
ではここで質問です。
したのシェルスクリプトを実行すると取得できる文字列は何になるでしょうか?
- grep -E ‘abc|123{3}’ 5_grep/grep_test.txt
-
abcc abcbc abcbcbc 12333 abcabcabc
- grep -E ‘abc|(123){3}’ 5_grep/grep_test.txt
-
abcc abcbc abcbcbc 123123123 abcabcabc
- grep -E ‘(abc|123){3}’ 5_grep/grep_test.txt
-
123123123 abcabcabc
シェルスクリプトのgrepは非常によく使用するので、このページを何度も読んで是非マスターしてください。