해당 줄에서 일치 항목을 검색한 다음 일치하지 않지만 일치하는 줄을 포함하는 컨텍스트 줄을 검색하려면 어떻게 해야 합니까?

해당 줄에서 일치 항목을 검색한 다음 일치하지 않지만 일치하는 줄을 포함하는 컨텍스트 줄을 검색하려면 어떻게 해야 합니까?

다음을 포함하는 파일이 있다고 가정해 보겠습니다.

⟫ 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이 이미 모든 컨텍스트 줄을 제거했기 때문에 끝에 / 플래그를 추가하는 것은 너무 늦습니다.-Bgrep -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어쩌면 간단한 스크립트일 수도 있습니다.단순한 sedruby스크립트를 더 쉽게 읽고 유지 관리할 수 있도록 작성할 수도 있습니다 .

답변1

두 명령을 함께 연결하면 내가 하려는 작업이 가능하지 않다고 생각합니다 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

단순히 두 개의 greps를 반대로 하면 원하는 대로 작동 하지 않고 precision이전 행을 제거하여 created_at두 번째 행과 일치 하지 않습니까 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

관련 정보