以下を含むファイルがあるとしましょう。
⟫ cat schema.rb
create_table "things", id: :serial, force: :cascade do |t|
t.string "other_column"
# ...
t.datetime "created_at"
end
create_table "users", id: :serial, force: :cascade do |t|
t.citext "email"
# ...
t.datetime "created_at", precision: 0
end
created_at
一致するすべての行を探したいのですがいいえマッチprecision:
。それは簡単です:
⟫ grep created_at schema.rb
t.datetime "created_at"
t.datetime "created_at", precision: 0
⟫ grep created_at schema.rb | grep -v precision:
t.datetime "created_at"
しかし、一致する行の一部のコンテキスト行を取得し、その行がどのブロックに表示されるかを確認するにはcreate_table
どうすればよいですか?-C
最初のgrepがすでにすべてのコンテキスト行を削除しているため、最後に/フラグを追加するのは遅すぎます。-B
grep -v
⟫ grep created_at schema.rb | grep -v precision: -B3
t.datetime "created_at"
しかし、最初の行に追加するのは時期尚早ですgrep
。grep -v
一致する行だけが削除され、一致する行を囲むコンテキスト行は削除されないためです。
⟫ grep created_at -B3 schema.rb | grep -v precision: -B3
create_table "things", id: :serial, force: :cascade do |t|
t.string "other_column"
# ...
t.datetime "created_at"
--
create_table "users", id: :serial, force: :cascade do |t|
t.citext "email"
# ...
最初の行に一致する行のコンテキスト行のみを含める方法はありますかgrep
(または同等にgrep -v
一致する行の周囲のコンテキスト行を削除します)?
create_table "things", id: :serial, force: :cascade do |t|
t.string "other_column"
# ...
t.datetime "created_at"
それともこれを行うための他のコマンドはありますか?
(sed
たぶん簡単なスクリプトかもしれません。シンプル sed
ruby
スクリプトを読みやすく保守しやすくするために作成することもできます。
答え1
2つのコマンドを一緒にリンクすると、私がやろうとしていることは可能ではないと思いますgrep
(コンテキスト行が各個々のgrep
コマンドに関連付けられているため)。
否定的な見通しは、私が望むものかもしれないと思いました。これにより、これらすべてをgrep
単一のコマンドで実行できます。
驚くべきことに、GNUはgrep
実際に正規表現のバック/フォワードをサポートしているようです。ただし、そのオプションを使用している場合にのみ可能です--perl-regex
。
grep
私が探していることを知らせるコマンドは次のとおりです。
⟫ grep --perl-regexp 'created_at(?!(.*precision:))' schema.rb -B3
create_table "things", id: :serial, force: :cascade do |t|
t.string "other_column"
# ...
t.datetime "created_at"
答え2
奇妙なソリューション
$ awk '/create_table/,/created_at/&&!/precision:/' schema.rb
create_table "things", id: :serial, force: :cascade do |t|
t.string "other_column"
# ...
t.datetime "created_at"
create_table "users", id: :serial, force: :cascade do |t|
t.citext "email"
# ...
t.datetime "created_at", precision: 0
end
$
次のいずれも実装されていません。正確に何が欲しいですか?しかし、どんな面でも役に立つ場合を備えておきます。
create_table 行に一致する sed ソリューションを印刷します。
create_table 行を見つけて見つかった場合は、保存バッファ "h" に保存します。 Create_at の後に精度を探し、見つかった場合は無視します。 Created_atのみを参照して見つかった場合は、印刷してください。
$ sed -n '/create_table/h;/created_at.*precision:/d;/created_at/{H;g;p}' schema.rb
create_table "things", id: :serial, force: :cascade do |t|
t.datetime "created_at"
$
create_table 行に一致する awk ソリューションを印刷します。
一致する create_table 行を具体的にターゲットにするには、次のようにします。
$ awk '/create_table/{t=$0}/created_at/&&!/precision:/{print t"\n"$0}' schema.rb
create_table "things", id: :serial, force: :cascade do |t|
t.datetime "created_at"
$
テーブル印刷のためのAwkソリューション
さらにステップが進み、一致する行を持つテーブル名のみを希望する場合は、次を使用できます。
$ awk '/create_table/{t=$2}/created_at/&&!/precision:/{print substr(t,2,length(t)-3)}' schema.rb
things
$
答え3
単に2つのgrep
sを逆にすると、必要に応じて動作せず、precision
前の行を削除してcreated_at
2番目の行と一致しませんかgrep
?
grep -v precision schema.rb | grep -A1 -B3 created_at
create_table "things", id: :serial, force: :cascade do |t|
t.string "other_column"
# ...
t.datetime "created_at"
end