Cần trợ giúp trong việc quét các tệp văn bản và tìm tất cả các từ giữa hai mẫu. Giống như nói rằng nếu chúng ta có một tệp .sql, cần quét và tìm tất cả các từ giữa 'và' ở đâu '. Grep chỉ có thể quét 1 dòng tại một thời điểm. Đối với yêu cầu này kịch bản unix tốt nhất để sử dụng là gì? sed, awk có những tính năng này? Chỉ vào bất kỳ ví dụ nào được đánh giá cao.Truy cập Grep Nhiều dòng, tìm tất cả các từ giữa hai mẫu
Trả lời
Sed có này:
sed -n -e '/from/,/where/ p' file.sql
In tất cả các ranh giới giữa một dòng với một from
và phù hợp với một where
.
Đối với một cái gì đó có thể bao gồm các dòng có cả từ và ở đâu:
#!/bin/sed -nf
/from.*where/ {
s/.*\(from.*where\).*/\1/p
d
}
/from/ {
: next
N
/where/ {
s/^[^\n]*\(from.*where\)[^\n]*/\1/p
d
}
$! b next
}
này (viết như một kịch bản sed) là hơi phức tạp hơn, và tôi sẽ cố gắng giải thích các chi tiết.
Dòng đầu tiên được thực hiện trên một dòng có chứa cả from
và where
. Nếu một dòng khớp với mẫu đó, hai lệnh sẽ được thực hiện. Chúng tôi sử dụng lệnh thay thế s
để chỉ trích xuất các phần giữa và từ đâu (bao gồm cả từ và vị trí). Hậu tố p
trong lệnh đó in ra dòng. Lệnh xóa xóa không gian mẫu (bộ đệm làm việc), tải dòng tiếp theo và khởi động lại tập lệnh.
Lệnh thứ hai bắt đầu thực thi một loạt lệnh (được nhóm theo dấu ngoặc móc) khi tìm thấy một dòng có chứa from
. Về cơ bản, các lệnh tạo thành một vòng lặp sẽ tiếp tục nối các dòng từ đầu vào vào vùng mẫu cho đến khi một dòng có một số where
được tìm thấy hoặc cho đến khi chúng ta đến được dòng cuối cùng.
Lệnh ":
" tạo nhãn, một điểm đánh dấu trong tập lệnh cho phép chúng tôi "nhảy" trở lại khi chúng tôi muốn. Lệnh N
đọc một dòng từ đầu vào và nối nó vào vùng mẫu (tách các dòng có ký tự dòng mới).
Khi tìm thấy where
, chúng tôi có thể in ra nội dung của không gian mẫu, nhưng trước tiên chúng ta phải làm sạch nó bằng lệnh thay thế. Nó tương tự với cái được sử dụng trước đây, nhưng bây giờ chúng ta thay thế .*
hàng đầu và theo sau bằng [^\n]*
, cho biết sed chỉ khớp với các ký tự không phải là dòng mới, kết hợp hiệu quả với từ trong dòng đầu tiên và ở vị trí cuối cùng. Lệnh d
sau đó xóa không gian mẫu và khởi động lại tập lệnh trên dòng tiếp theo.
Lệnh b
sẽ chuyển đến nhãn, trong trường hợp của chúng tôi, nhãn next
. Tuy nhiên, địa chỉ $!
nói rằng nó không nên được thực hiện trên dòng cuối cùng, cho phép chúng tôi rời khỏi vòng lặp. Khi rời khỏi vòng lặp theo cách này, chúng tôi đã không tìm thấy một where
tương ứng, vì vậy bạn có thể không muốn in nó.
Lưu ý tuy nhiên, điều này có một số hạn chế. Các trường hợp sau sẽ không được xử lý như mong đợi:
from ... where ... from
from ... from
where
from
where ... where
from
from
where
where
Xử lý các trường hợp này cần thêm mã.
Hope this helps =)
đơn giản, nhưng tôi không nghĩ rằng đó là những gì OP cần .... – Kent
Cảm ơn, đã cứu tôi một đống RTFM'ing :-) –
bất kỳ ý tưởng nào về số dòng cũng in ở đầu dòng phù hợp nếu mẫu khớp với –
Với GNU awk, do đó bạn có thể thiết lập RS đến một RE:
gawk -v RS='[[:space:]]+' '
/where/ { found=0 }
found { print }
/from/ { found=1 }
' file
Trên đây giả sử bạn không muốn "từ" và "ở đâu" in, di chuyển các đường xung quanh nếu cần thiết để làm khác.
Trong trường hợp nó giúp, các thành ngữ sau đây mô tả làm thế nào để chọn một loạt các hồ sơ cho một mô hình cụ thể để phù hợp với:
a) In tất cả các bản ghi từ một số mẫu:
awk '/pattern/{f=1}f' file
b) In tất cả các hồ sơ sau khi một số mẫu:
awk 'f;/pattern/{f=1}' file
c) In kỷ lục thứ N sau khi một số mẫu:
awk 'c&&!--c;/pattern/{c=N}' file
d) In mọi kỷ lục ngoại trừ các bản ghi thứ N sau khi một số mẫu:
awk 'c&&!--c{next}/pattern/{c=N}1' file
đ) In các hồ sơ tồn sau khi một số mẫu:
awk 'c&&c--;/pattern/{c=N}' file
f) In mọi kỷ lục ngoại trừ Bản ghi N sau một số mẫu:
awk 'c&&c--{next}/pattern/{c=N}1' file
g) In bản ghi nhớ N rds từ một số mẫu:
awk '/pattern/{c=N}c&&c--' file
Tôi đã thay đổi tên biến từ "f" cho "tìm thấy" thành "c" cho "đếm" nơi thích hợp như đó là biểu cảm nhiều hơn những gì biến thực sự IS.
Bạn có thể sử dụng ed
cho điều này, nó cho phép bù dương và âm cho phạm vi regex. Nếu đầu vào là:
seq 10 | tee > infile
1
2
3
4
5
6
7
8
9
10
ống trong lệnh để ed
:
<<< /3/,/6/p | ed -s infile
ví dụ: in tất cả mọi thứ giữa các dòng có chứa 3
và 6
.
Kết quả:
3
4
5
6
Để có được một dòng hơn ở mỗi đầu:
<<< /3/-1,/5/+1p | ed -s infile
Kết quả:
2
3
4
5
6
7
Hoặc cách khác xung quanh:
<<< /3/+1,/6/-1p | ed -s infile
Kết quả:
4
5
Để trở về chỉ là một chuỗi trong hai chuỗi cho trước, dọc theo dòng của awk
(mà không nhận được điên) Tôi chỉ cần chạy script này rất bằng phẳng, cách rườm rà trong tow:
.\gnucoreutils\bin\awk "{startstring = \"RETURN STUFF AFTER ME \"; endstring = \"RETURN STUFF BEFORE ME\"; endofstartstring = index($0,startstring)+length(startstring); print substr($0,endofstartstring,index($0,endstring)-endofstartstring)}" /dev/stdin
Lưu ý rằng tôi đang sử dụng cmd.exe
(trình thông dịch lệnh với Windows) và the gnuwin32 awk, vì vậy hãy nhớ "dấu ngoặc kép" và^\ escape ký tự^\:
GNU Awk 3.1.6
Copyright (C) 1989, 1991-2007 Free Software Foundation.
Hãy chỉ ra các lỗi.
dụ:
echo "hello. RETURN STUFF AFTER ME i get returned RETURN STUFF BEFORE ME my face is melting" | .\gnucoreutils\bin\awk "{startstring = \"RETURN STUFF AFTER ME \"; endstring = \" RETURN STUFF BEFORE ME\"; endofstartstring = index($0,startstring)+length(startstring); print substr($0,endofstartstring,index($0,endstring)-endofstartstring)}" /dev/stdin
i get returned
tôi đã có thể thực hiện điều này chỉ sử dụng grep:
#> grep -A#### "start pattern" file | grep -B#### "end pattern"
Vấn đề là tôi đã phải tìm đúng lượng đường đưa vào A và B các tùy chọn, giống nhau. Hy vọng điều này sẽ giúp
bạn có thể dán nội dung mẫu sql không? ví dụ. có bao nhiêu từ ... ở đâu trong tệp của bạn? có trường hợp "từ" và "ở đâu" trong cùng một dòng không? tất cả những điều này làm cho việc trích xuất logic khác nhau. – Kent
Câu trả lời này cũng có thể áp dụng: https://stackoverflow.com/a/48022994/2026975 – imriss