Hiển thị tất cả các tập tin lên đến trận đấu


71

grep --before-context 5 hiển thị 5 dòng trước trận đấu.

Tôi muốn thể hiện mọi thứ trước trận đấu.
Làm grep --before-context 99999999sẽ làm việc nhưng nó không ... rất chuyên nghiệp.

Làm thế nào để hiển thị tất cả các tập tin lên đến trận đấu?

Câu trả lời:


95

Sed là tốt hơn cho điều đó.

Cứ làm đi:

sed '/PATTERN/q' FILE

Nó hoạt động như thế này:

Đối với mỗi dòng, chúng tôi xem nếu nó phù hợp /PATTERN:

  • nếu có, chúng tôi in nó và thoát
  • mặt khác, chúng tôi in nó

Đây là giải pháp hiệu quả nhất, vì ngay khi nhìn thấy PATTERN, nó đã thoát ra. Nếu không q, sed sẽ tiếp tục đọc phần còn lại của tập tin và không làm gì với nó. Đối với các tập tin lớn, nó có thể làm cho một sự khác biệt.

Thủ thuật này cũng có thể được sử dụng để mô phỏng head:

sed 10q FILE

Chỉ cần thử, nó chỉ xuất ra dòng đầu tiên của tệp ... mặc dù kết quả khớp ở dòng 38.
Nicolas Raoul

Hoạt động tốt cho tôi. Bạn có thể cho một ví dụ về đầu vào và đầu ra thực tế? Và lệnh bạn đang chạy như vốn có.
Mikel

Tôi đã thử lệnh của bạn trước khi bạn chỉnh sửa nó, đó là: sed '/ PATTERN / p; q' FILE
Nicolas Raoul

7
Tôi nên làm gì nếu tôi không muốn in dòng với mẫu phù hợp?
tommy.carstensen

4
@ tommy.carstensen: sed '/PATTERN/Q' FILEsẽ bỏ qua dòng phù hợp. Qlà một phần mở rộng GNU, vì vậy nó sẽ không hoạt động với bất kỳ sed nào.
Alex O

37

sed có thể thay thế hầu hết các chức năng của grep.

sed -n '1,/<pattern>/ p' <file>

Điều này có nghĩa là in từ dòng đầu tiên cho đến khi mẫu được khớp.

Một vài ví dụ

sed -n '/<pattern>/,$ p' <file> # from pattern to end of file
sed -n '/<pattern1>/,/<pattern2>/ p' <file> # from pattern1 to pattern2

3
Lệnh này là tốt, nhưng bạn có thể làm tốt hơn. Bằng cách này, nó đọc toàn bộ tập tin, nhưng có thể thoát ngay khi tìm thấy kết quả khớp.
Mikel

3
Tôi nên làm gì nếu tôi không muốn in dòng với mẫu phù hợp?
tommy.carstensen

34

in lên và bao gồm cả trận đấu:

awk '{print} /pattern/ {exit}' filename
sed '/pattern/q' filename

in lên NHƯNG KHÔNG bao gồm trận đấu:

awk '/pattern/ {exit} {print}' filename
sed '/pattern/Q' filename

11
QAfaik mát mẻ nhưng cụ thể của gnu, sed -n '/pattern/!p;//q'sẽ dễ mang theo hơn.
don_crissti

@don_crissti: bạn nên làm cho nó một câu trả lời, tôi nghĩ rằng đó là một trong những tốt (: Tôi là một chút tò mò cách hoạt động, mặc dù tôi tin. !làm cho páp dụng đối với dòng không phù hợp pattern, nhưng sau đó //qbối rối cho tôi ...
JWD

2
@don_crissti: ah, tôi hiểu rồi - //có nghĩa là "biểu thức chính quy trước đó" (tôi nghĩ nó có nghĩa là "khớp với chuỗi rỗng"). Tôi nghĩ rằng một phiên bản ngắn hơn của cùng một giải pháp là : sed -n '/pattern/q;p?
JWD

@jwd - thực sự, đó là ngắn hơn. 👍
don_crissti

1

Các grepphương thức GNU thuần túy sau đây không hiệu quả.

Tìm kiếm mọi thứ cho đến phiên bản đầu tiên của chuỗi " foo " trong thanh tệp , sử dụng ba greps:

grep -m 1 -B $(grep -n -m 1 foo bar | grep -o '^[0-9]*') foo bar

Phù hợp với phiên bản cuối cùng của " foo ":

grep -oPz "(?s)[^\n]*${s}.*?\n.*?foo.*?\n" bar

Lưu ý: chi tiết cuối cùng grepcó thể được tìm thấy trong: Regex (grep) cho tìm kiếm nhiều dòng cần thiết .


Tại sao người ta lại muốn sử dụng 7 grepgiây (+ pcre) khi vấn đề chỉ đơn giản là chạy một lệnh sedgọi duy nhất : sed 'x;/./G;//!x;/foo/p;//s/.*//;x;d'??
don_crissti

@don_crissti, sedmã của bạn có vẻ đáng để trả lời, hoặc có thể được thêm vào một trong những mã khác. Re 7 greps: Bởi vì không có grepcâu trả lời ... (cộng với, câu trả lời giúp thể hiện tại sao không.)
agc

Đó không phải là mã của tôi, chỉ cần nhấp vào nó ... Ngay cả khi đó là mã của tôi, nó không trả lời Q ở đây vì vậy tôi sẽ không đăng nó dưới dạng câu trả lời.
don_crissti

1

Thêm vào câu trả lời của Mikel ở trên ...


Để in tất cả các dòng lên đến, nhưng không bao gồm , dòng đầu tiên FILEchứa PATTERN, hãy thử:

  • sed '/.*PATTERN.*/{s///;q;}' FILE

Điều này khớp với toàn bộ dòng chứa mẫu, thay thế nó bằng một dòng trống, sau đó thoát ra mà không xử lý phần còn lại của tệp.


Kịch bản sau:

Cách dễ nhất / rõ ràng nhất mà tôi có thể nghĩ ra để ngăn việc in thêm một dòng mới ở cuối (không liên quan đến công cụ khác), là chạy lại sed và xóa dòng cuối cùng mới:

sed '/.*PATTERN.*/{s///;q;}' FILE | sed '$d'

... và vì hiện tại chúng tôi đang xóa dòng đó, công việc trước đây của chúng tôi là không cần thiết và chúng tôi có thể đơn giản hóa để:

sed '/PATTERN/q' FILE | sed '$d'

Câu trả lời của Glenn - và nhận xét của tôi ở đó - chỉ ra cách thực hiện với một sedlời mời duy nhất .
don_crissti

(Cảm ơn cho điều đó -. Tôi thấy nhận xét của bạn về câu trả lời AGC của nhưng một trong hai bỏ lỡ một trong những khác hoặc chỉ đọc lướt nó bởi vì bộ não của tôi không thích đôi âm) Kể từ khi tôi đã sử dụng này trong cả một tcshvà một bashbí danh, tôi cần phải chắc chắn rằng tôi có một giải pháp một dòng tương đối ngắn gọn, hoạt động trong cả tiêu chuẩn và GNU sed(cho tính di động); tất cả các yêu cầu mà sự đóng góp của bạn rất có thể đã đáp ứng. Là một người sử dụng sed rất hiếm khi, yêu cầu quan trọng nhất của tôi là một cái gì đó mà tôi có thể nhanh chóng hiểu khi tôi muốn dễ dàng chỉnh sửa hoặc tái mục đích đó năm kể từ bây giờ.
Jim Grisham

1

Đối với những người chọn chỉ nhớ các công cụ cơ bản trong công việc hàng ngày và sẵn sàng chấp nhận các giải pháp kém thanh lịch và kém hiệu quả hơn:

head -n $(grep -n pattern filename | cut -d: -f1) filename

Nếu lệnh này là cho một kịch bản thì tôi sẽ tìm kiếm các giải pháp thanh lịch hơn (và có thể hiệu quả). Nếu đây là lệnh một lần hoặc kịch bản vứt đi thì tôi không quan tâm.


1
Ý tưởng hay, nhưng ba lệnh khi một người sẽ làm.
Mikel

1
Biết những điều cơ bản thực sự là rất tốt. Biết công cụ phù hợp cho công việc là tốt hơn, mặc dù.
soulmerge

Nếu lệnh này là cho một kịch bản thì tôi sẽ tìm kiếm các giải pháp thanh lịch hơn (và có thể hiệu quả). Nếu đây là lệnh một lần (hoặc tập lệnh vứt đi), thì tôi không quan tâm.
lesmana

0

Bạn cũng có thể sử dụng một trong những điều sau đây

tac ./test | grep -B $(cat ./test | wc -l) -m 1 'pattern'|tac 

hoặc là

tac ./test |head -n $(tac ./test | grep -n 'pattern' | cut -d: -f1 | head -n 1)|tac

hoặc là

tac ./test |sed ':a;N;$!ba;s/\n/'"pattern"'/g' | sed 's/'"patternpattern"'/\n/g'|head -n 1|sed 's/'"pattern"'/\n/g'|tac

Tùy chọn đầu tiên rất giống với những gì OP đề xuất, chỉ đảm bảo rằng ti hiển thị đủ các dòng trước ngữ cảnh bằng cách đếm các dòng trong tệp

Tùy chọn thứ hai tìm kiếm số dòng của trận đấu đầu tiên (bạn cũng có thể thay đổi số đó bằng cách thay đổi 'đầu' bên trong) và sử dụng đầu trên số đó

Tùy chọn cuối cùng thay thế tất cả các dòng mới bằng trận đấu và thay thế hai trận đấu liền kề bằng một dòng mới. Đầu ra của điều này là một dòng cho mỗi khối văn bản giữa hai kết quả khớp. Sau đó, nó sử dụng 'head' để chọn dòng đầu tiên (thay đổi khối văn bản cho đến khi khớp đầu tiên) khớp và hơn là truyền lại mỗi trận đấu sang một dòng mới. tùy chọn này chỉ hoạt động nếu tệp có định dạng sau

pattern
texttexttext
texttexttext texttexttext
texttexttexttexttexttexttexttexttext
pattern
texttexttext
pattern 
texttexttext
texttexttexttexttexttexttexttexttext

và kể từ đó trở đi


2
xem xét giải thích làm thế nào những thứ này hoạt động, đặc biệt bởi vì sedlệnh đó ở phía dưới là loại sởn gai ốc.
strugee

tùy chọn đầu tiên rất giống với những gì OP đề xuất, chỉ đảm bảo rằng ti hiển thị đủ số kines trước ngữ cảnh bằng cách đếm các dòng trong filr,
user122778 10/07/2015
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.