京橋のバイオインフォマティシャンの日常

まずは、データ分析、コマンドラインのメモとして

grepコマンドで文字列処理をやってみた件【その2】検索語のヒット数カウントとか検索語の前後文字の抽出とか色々

grepコマンドによる文字列処理をやってみた」の続編である。

以前扱えていなかった内容をやっていきたい。

grepコマンドの基本については過去の記事を参照のこと。

skume.hatenablog.com

skume.hatenablog.com

まずは、サンプルデータをダウンロードする

$ svn export  https://github.com/kumeS/Blog/trunk/grep_practice_02

$ cd ./grep_practice_02

# test.txtを使っていく。
$ cat test.txt

#abcde
#ABCDE
#
#abcdefghijklmnopqrstuvwxyz
#ABCDEFGHIJKLMNOPQRSTUVWXYZ
#
#12345abcde67890fghij
#12345abcde67890fghij

内容

検索語に一致した文字列のみを抜き出して出力する

grep -oを使うと、検索後と同じものが、ヒットした文字列として出力される。

#'abc'で検索すると、5個ヒット
$ grep -o 'abc' test.txt
#abc
#abc
#abc
#abc
#abc

# -o を入れずに検索すると、'abc'を含む行数の4個でヒット
$ grep 'abc' test.txt
#abcdeabcde
#abcdefghijklmnopqrstuvwxyz
#12345abcde67890fghij
#12345abcde67890fghij

#'fghij'で検索すると、3個ヒット
$ grep -o 'fghij' test.txt
#fghij
#fghij
#fghij

大文字・小文字を区別せず、検索語に一致した文字列のみを抜き出して出力する

grep -o -iを使うと、大文字・小文字が区別されずに、ヒットした文字列が出力される。

#'abc' or 'ABC'で検索され、8個ヒット
$ grep -o -i 'abc' test.txt
#abc
#abc
#ABC
#ABC
#abc
#ABC
#abc
#abc

# -i のみで検索すると、6個ヒット
$ grep -i 'abc' test.txt
#abcdeabcde
#ABCDEABCDE
#abcdefghijklmnopqrstuvwxyz
#ABCDEFGHIJKLMNOPQRSTUVWXYZ
#12345abcde67890fghij
#12345abcde67890fghij

#'fghij' or 'FGHIJ' で検索され、4個ヒット
$ grep -o -i 'fghij' test.txt
#fghij
#FGHIJ
#fghij
#fghij

検索語に一致した文字列の数をカウントする【部分一致検索】

grep -ogrep -cを使うと、検索語に一致した文字列数が出力される。

このとき注意することとしてコマンドを分けずに、grep -o -cにすると、行数カウントになる。

#'abc'で検索して、'abc'をカウントすると、5個ヒット
$ grep -o 'abc' test.txt | grep -c 'abc'
#5

# -o -c にすると、4個ヒットで、行数カウントになる
$ grep -o -c 'abc' test.txt
#4

#'fghij'で検索すると、3個ヒット
$ grep -o 'fghij' test.txt | grep -c 'fghij'
#3

検索語に一致した箇所の前後の行を出力する

grep -Cを使うと、前後の行(行数指定)を一緒に出力できる。

#前後1行を出力する
$ grep -C 1 'hijklmn' test.txt
#
#abcdefghijklmnopqrstuvwxyz
#ABCDEFGHIJKLMNOPQRSTUVWXYZ

#前1行、後3行を出力する
$ grep  -B 1  -A 3 'hijklmn' test.txt
#123456
#abcdefghijklmnopqrstuvwxyz
#ABCDEFGHIJKLMNOPQRSTUVWXYZ
#
#12345abcde67890fghij

grep -B -Aを使うと、-Bで検索語前の行数、-Aで検索語後の行数を指定できる。

検索語に一致した箇所の前後の文字列を出力する

上記で、行レベルで出力する方法を紹介したが、 正規表現. (ピリオド)を使うと、前後の文字列も出力できる。

#検索語を抜き出して表示
$ grep -o 'efghijk' test.txt
#efghijk

#検索語の前4文字も含めて出力
$ grep -o '....efghijk' test.txt
#abcdefghijk

#検索語の後4文字も含めて出力
$ grep -o 'efghijk....' test.txt
#efghijklmno

#検索語の前4文字、後4文字も含めて出力
$ grep -o '....efghijk....' test.txt
#abcdefghijklmno

また、検索語を「変数」で指定することもできる。

TERMS=$"efghijk" ; grep -o "....$TERMS...." test.txt
#OR
TERMS=$'efghijk' ; grep -o "....$TERMS...." test.txt

#abcdefghijklmno

やってみると、'"の組み合わせが重要らしい。

;は、複数文を繋げて書く文法である。

検索語を行番号付きで出力する

grep -nを使うと、行番号付きで出力される。

#'abc'行を行番号付きで出力
$ grep -o -n 'abc' test.txt
#1:abc
#abc
#4:abc
#7:abc
#8:abc

$ grep -n 'abc' test.txt
#1:abcdeabcde
#4:abcdefghijklmnopqrstuvwxyz
#7:12345abcde67890fghij
#8:12345abcde67890fghij

#'fghij'行を行番号付きで出力
$ grep -o -n 'fghij' test.txt
#4:fghij
#7:fghij
#8:fghij

検索語の行番号のみを出力する

行番号のみを出力するには、sedとの組み合わせで行う。

#'abc'行を行番号のみ出力
$ grep -n 'abc' test.txt | sed -e 's/:.*//g'
#1
#4
#7
#8

#'fghij'行を行番号のみ出力
$ grep -n 'fghij' test.txt | sed -e 's/:.*//g'
#4
#7
#8

grepのエラーメッセージを消す

そのままではあまり使わないけど、プログラムを組むときには役に立つかも。

#フォルダに実行するとエラーが出る
$ grep 'abcd' test
grep: test: Is a directory

$ grep -s 'abcd' test
#OR
$ grep --no-messages 'abcd' test
#エラーメッセージの非表示

まとめ

grepコマンドは結構役に立つので、一通り覚えておくと、 いろいろなテキストの前処理とかに使えそう。

補足

正規表現のまとめ

正規表現 (Regular Expression)は、文字列のパターン・マッチングなどの表記法として使用する。

また、メタキャラクタとは、文字列のパターンを表す特殊な記号のことを指す。

メタキャラク そのメタキャラクタが意味すること
. 任意の一文字
* 前にある文字の0回以上の繰り返し
+ 前にある文字の1回以上の繰り返し
? 前にある文字の0回あるいは1回の意味
^ 指定した文字が文頭
$ 指定した文字が文末
[ ] 指定した複数の文字の中のいずれか
{ } 前にある文字の指定した回数の繰り返し
\w 英数文字またはアンダーバー。[a-zA-Z0-9_]と同等
\W \w 以外の文字
\d 数値文字。[0-9]と同等
\D 数値以外の文字。[^0-9]と同等
\s 空白文字
\S 空白以外の文字
\b ワードの先頭、あるいは末尾にマッチ
\B ワード内の文字列にマッチ
\A 文字列の最初にマッチ
\Z 文字列の最後にマッチ
\t タブ
\n 改行
\r キャリッジリターン

参考

www.wakuwakubank.com

webplus8.com

www.gadgety.net