LoginSignup
5
3

More than 3 years have passed since last update.

grep の -f オプションでうまく検索できない場合の対処法

Last updated at Posted at 2020-08-04

はじめに

grep -fを使っていて、「検索文字列が末尾にある行」しかヒットしない※という事が起こった場合
改行コードが原因かもしれません。
sedechoで改行コードを直してやればうまくいくようになります、という内容です。

(※Windowsの場合。Macだと違う挙動かも?)


※ ファイル内の各行を検索文字列に使用したい場合には、grep -fや、while文で1行ずつ読み込む(while read line)などの方法が使えます。

・grep -f オプション

grep -f [検索文字列ファイル] [検索対象ファイル]

・while文を利用

while read line
do
grep "$line" [検索対象ファイル]
done < [検索文字列ファイル]

(※この書き方の場合、[検索文字列ファイル]の最終行で改行している必要あり(じゃないと最終行だけ読み込まれない)。複数条件に該当する行は何度も出現してしまうので注意)


起こっている事

下記のように、ファイル内の各行で検索を掛けたときに、「検索文字列が末尾にある行」しか選択されないという現象が起こることがあります(というか起こった)。

検索文字列ファイル(file.txt)
AAA
BBB
検索対象ファイル(test.txt)
AAAxxxxxxxx
xxxxxAAAxxx
xxxxxxxxAAA
BBBx BBB xx
xxxxxxxxBBB
xxAAAxxBBBx
xxxCCCxxxxx
検索文字列が末尾にある行しか選択されない
$ grep -f file.txt test.txt
xxxxxxxxAAA
xxxxxxxxBBB

$ while read line
> do
> grep "$line" test.txt
> done < file.txt
xxxxxxxxAAA
xxxxxxxxBBB

対処法の例

1. sedコマンド

なんでもいいので適当にsedを使って[検索文字列ファイル]を作り直すことで、うまく動くようになります。

$ sed 's/^//' file.txt > file2.txt
$ grep -f file2.txt test.txt
AAAxxxxxxxx
xxxxxAAAxxx
xxxxxxxxAAA
BBBx BBB xx
xxxxxxxxBBB
xxAAAxxBBBx

2. echoコマンド

while文の方では、echo$lineを読み直す方法でも、うまくいきます。

$ while read line
> do
> grep `echo $line` test.txt
> done < file.txt
AAAxxxxxxxx
xxxxxAAAxxx
xxxxxxxxAAA
xxAAAxxBBBx  ##
BBBx BBB xx
xxxxxxxxBBB
xxAAAxxBBBx  ## 複数条件に該当する場合は何度も出現する

その他の対処法

その他の改行コード変換方法の例
改行コードの変換

解説

今回の挙動の原因は、WindowsとUnixで改行コードが異なることでした。
つまりWindows上で作成したファイルを検索文字列として利用すると、\r の部分が検索の妨げになる("検索文字列 + \r"を探す)ため、末尾に検索文字列がある場合にしかヒットしなかったというわけです。
(実際、file.txtの2行目で改行をなくすと、"BBB"の方は正常に検索されるようになります。また逆にtest.txtsedを実行して、改行コードをCRLFからLFに直すと何も出力されなくなります)

OS 改行コード 「od -c」での見え方
Unix LF \n
Mac(OSX) LF \n
Mac(OS9) CR \r
Windows CR+LF \r\n

引用:改行コードの確認

file.txtの2行目(BBB)で改行しない場合
$ grep -f file.txt test.txt
xxxxxxxxAAA
BBBx BBB xx
xxxxxxxxBBB
xxAAAxxBBBx
検索対象ファイル(test.txt)にsedを実行した場合(何も出力されない)
$ sed 's/^//' test.txt > test2.txt
$ grep -f file.txt test2.txt


sedechoを使用すると、改行コードがCRLF(\r\n)からLF(\n)に変換されるため、検索がうまくいくようになります。

sedコマンド前後
## ---------------------- sed 前 (CRLF)
$ file file.txt
file.txt: ASCII text, with CRLF line terminators

$ od -c file.txt
0000000   A   A   A  \r  \n   B   B   B  \r  \n
0000012

## ---------------------- sed 後 (LF)
$ file file2.txt
file2.txt: ASCII text

$ od -c file2.txt
0000000   A   A   A  \n   B   B   B  \n
0000010
echoコマンド前後
$ cat hoge.txt
hoge

$ while read line
> do
> echo `echo $line` > hoge2.txt
> done < hoge.txt

## ---------------------- echo 前 (CRLF)
$ od -c hoge.txt
0000000   h   o   g   e  \r  \n
0000006

## ---------------------- echo 後 (LF)
$ od -c hoge2.txt
0000000   h   o   g   e  \n
0000005

参考:
【 sed 】コマンド(基礎編)――テキストファイルを編集する
Windowsのsedで置換して変わった改行コードをLFからCRLFに戻す方法

なお、Macの場合、以前のMacOSではCRが採用されていましたが、MacOSX以降はUnix系OSと同じLFとなっているとのことです。

[Linux] 改行コードを変換する

5
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
3