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

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

（※Windowsの場合。Macだと違う挙動かも？）

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

#### ・while文を利用
`while read line
do
grep "$line" [検索対象ファイル]
done < [検索文字列ファイル]`

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

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

```tex:検索文字列ファイル（file.txt）
AAA
BBB
```

```tex:検索対象ファイル（test.txt）
AAAxxxxxxxx
xxxxxAAAxxx
xxxxxxxxAAA
BBBx BBB xx
xxxxxxxxBBB
xxAAAxxBBBx
xxxCCCxxxxx
```

```sh:検索文字列が末尾にある行しか選択されない
$ grep -f file.txt test.txt
xxxxxxxxAAA
xxxxxxxxBBB

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

## 対処法の例
#### 1. sedコマンド
なんでもいいので適当に`sed`を使って**[検索文字列ファイル]**を作り直すことで、うまく動くようになります。

```sh
$ 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`を読み直す方法でも、うまくいきます。

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

---
#### その他の対処法
その他の改行コード変換方法の例
・[改行コードの変換](http://osksn2.hep.sci.osaka-u.ac.jp/~taku/osx/crlf.html)

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

| OS         | 改行コード | 「od -c」での見え方 |
|------------|------------|---------------------|
| Unix       | LF         | \n                  |
| Mac（OSX） | LF         | \n                  |
| Mac（OS9） | CR         | \r                  |
| Windows    | CR+LF      | \r\n                 |
引用：[改行コードの確認](https://qiita.com/Dace_K/items/76a1873ed4ab327254b5)

```sh:file.txtの2行目（BBB）で改行しない場合
$ grep -f file.txt test.txt
xxxxxxxxAAA
BBBx BBB xx
xxxxxxxxBBB
xxAAAxxBBBx
```

```sh:検索対象ファイル（test.txt）にsedを実行した場合（何も出力されない）
$ sed 's/^//' test.txt > test2.txt
$ grep -f file.txt test2.txt

```

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

```sh: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
```

```sh: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 】コマンド（基礎編）――テキストファイルを編集する](https://www.atmarkit.co.jp/ait/articles/1610/06/news021.html)
・[Windowsのsedで置換して変わった改行コードをLFからCRLFに戻す方法](https://qiita.com/ponsuke0531/items/222abdb044bcebcc0379)

なお、Macの場合、以前のMacOSではCRが採用されていましたが、MacOSX以降はUnix系OSと同じLFとなっているとのことです。
>[[Linux] 改行コードを変換する](https://blog.katsubemakito.net/linux/convert-linebreaks)