다음을 포함하는 파일이 있다고 가정해 보겠습니다.
⟫ 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
두 명령을 함께 연결하면 내가 하려는 작업이 가능하지 않다고 생각합니다 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
단순히 두 개의 grep
s를 반대로 하면 원하는 대로 작동 하지 않고 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