Linuxにおいて指定パス配下に存在する任意の拡張子を持つファイルを検索する方法

# はじめに
みなさん、こんにちは **torihazi**です

Vscodeにおいてファイル横断検索と同等のことをlinuxでやるには

どうしたらいいんだろうかと考え、至った結論です。

実用性は、不明です。

本業で似たようなことをやったことがありました。

# 方法
今回は rails をやっている最中なので`erb`と`rb`のものを取得します。
1. `find 任意のパス -type f -name "*.erb" -o -name "*.rb"`

以上になります。

# 解説
解説できるほど強くないので語れはしません。以下自分の理解です

- find
検索やファイルの実行など色々できるコマンドです。オプションが山のようにあります。全ては知りません。
私は大抵検索用途です。
- パス指定
検索を開始する最上階のパスを指定します。
今いるディレクトリ配下のを検索対象とするなら`./`、`~/Documents/sample`みたいな形でフルパス指定でも可能です。
違いとしては出力結果です。フルパスで出力されるか相対パスで出力されるかの違いです。
- -type
検索対象のタイプ（ファイルなのかディレクトリなのかとか)を指定します。
今回はファイルなので`-type f`を指定します。
- -name
ファイル名の検索条件を指定します。正規表現可能です。
例えば拡張子がerbなら"*.erb"みたいに

- -o
論理演算子 ORのことです。
今回は拡張子が`erb`もしくは`rb`のファイルを検索したいので
`-name "*.erb" -o -name "*.rb"`としています。
ちなみに ANDは`-a`です。

以上をくっつけると出力はこんな感じになります。
コマンドイメージ
```
# find ./ -type f -name "*.erb" -o -name "*.rb"
~~~~
.//app/mailers/order_detail_mailer.rb
.//app/mailers/application_mailer.rb
.//app/models/order_detail.rb
.//app/models/product.rb
.//app/models/order.rb
.//app/models/cart_product.rb
.//app/models/application_record.rb
.//app/models/cart.rb
.//app/models/task.rb
.//app/jobs/application_job.rb
.//app/controllers/cart_products_controller.rb
.//app/controllers/application_controller.rb
.//app/controllers/carts_controller.rb
.//app/controllers/tasks_controller.rb
.//app/controllers/orders_controller.rb
.//app/controllers/admin/products_controller.rb
.//app/controllers/products_controller.rb
```

# 応用？
先のコマンドで出力されたファイルの中から特定の文字を含むファイルを検索したいとします。

今回なら`name`とでもします。

このように`任意の拡張子を持つファイル検索 -> その中から特定の文字を含むファイルを検索`をワンライナー実現するには以下の流れで行います。

※ワンライナーとは文字のごとく複数コマンドとかを一行に繋げて書く方法のこと？です。

1. find ./ -type f -name "*.erb" -o -name "*.rb"を実行
1. その結果に対して それぞれに`grep "name"`を実行する

2番については`xargs`を使用します。
このコマンドは前コマンドの結果を引数に取ることができるコマンドです。

1,2をくっつけると以下のようになります。
`find ./ -type f -name "*.erb" -o -name "*.rb" | xargs grep -n "name"`
※grepの`-n`は出現した行の行数を一緒に表示してくれるオプションです。

出力イメージは以下のようになります。
```
# find ./ -type f -name "*.erb" -o -name "*.rb" | xargs grep "name"
~~~
.//app/models/product.rb:  validates :name, presence: true, length: { maximum: 20 }
.//app/models/order.rb:  validates :first_name, presence: true, length: { maximum: 10 }
.//app/models/order.rb:  validates :last_name, presence: true, length: { maximum: 10 }
.//app/models/order.rb:  validates :user_name, presence: true, length: { maximum: 20 }
.//app/models/order.rb:  validates :cardholder_name, presence: true,
.//app/controllers/orders_controller.rb:      :first_name,
.//app/controllers/orders_controller.rb:      :last_name,
.//app/controllers/orders_controller.rb:      :user_name,
.//app/controllers/orders_controller.rb:      :cardholder_name,
.//app/controllers/orders_controller.rb:      product_name: item.product.name,
まだまだ続く・・・
```

# 応用のさらに応用？
ここまでくると実用性があるかどうかはわかりません。
例えば`上司からその検索結果をファイルごとに分けて表示してよ`などと言われた場合です。
Vscodeや専用のテキストエディタが使えず、linuxのターミナルだけでやらざるを得ない人用です。
スクリプトを書きました。汚いかもしれませんが、私のレベルはこんなもんです。

```searchAndExtract.sh
#!/bin/sh

file1="$HOME/Documents/file1.txt"
file2="$HOME/Documents/file2.txt"

find $HOME/Documents/rails_ec -type f -name "*.erb" -o -name "*.rb" >> $file1

while read line
do
    grep -n "name" $line > /dev/null 2>&1

    if [[ $? == 0 ]];then
        echo "$line" >> $file2
        grep -n "name" $line >> $file2
    else
        continue
    fi
    echo "" >> $file2
done < $file1
```

このwhileループに入る際に grepを2度やっているのがどうも癪に触りますが、どう直せばいいか
わかりませんでした。

ちなみに結果は以下のようになります。
```
/Users/hoge/Documents/rails_ec/app/models/product.rb
9:  validates :name, presence: true, length: { maximum: 20 }

/Users/hoge/Documents/rails_ec/app/models/order.rb
6:  validates :first_name, presence: true, length: { maximum: 10 }
7:  validates :last_name, presence: true, length: { maximum: 10 }
8:  validates :user_name, presence: true, length: { maximum: 20 }
13:  validates :cardholder_name, presence: true,

/Users/hoge/Documents/rails_ec/app/controllers/orders_controller.rb
43:      :first_name,
44:      :last_name,
まだまだ続く・・・
```

# 終わりに
まだまだですね。頑張りたいです。

何度も書いていますが、私は数年前まではPCろくに知らない初心者でした。

なのでみなさんなら理解は秒です。

頑張ってください。僕も頑張ります。