はじめに
みなさん、こんにちは torihaziです
Vscodeにおいてファイル横断検索と同等のことをlinuxでやるには
どうしたらいいんだろうかと考え、至った結論です。
実用性は、不明です。
本業で似たようなことをやったことがありました。
方法
今回は rails をやっている最中なのでerb
とrb
のものを取得します。
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
とでもします。
このように任意の拡張子を持つファイル検索 -> その中から特定の文字を含むファイルを検索
をワンライナー実現するには以下の流れで行います。
※ワンライナーとは文字のごとく複数コマンドとかを一行に繋げて書く方法のこと?です。
- find ./ -type f -name ".erb" -o -name ".rb"を実行
- その結果に対して それぞれに
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のターミナルだけでやらざるを得ない人用です。
スクリプトを書きました。汚いかもしれませんが、私のレベルはこんなもんです。
#!/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ろくに知らない初心者でした。
なのでみなさんなら理解は秒です。
頑張ってください。僕も頑張ります。