Thuyết phục grep để xuất tất cả các dòng, không chỉ những dòng có khớp


121

Nói rằng tôi có tập tin sau:

$ cat test

test line 1
test line 2
line without the search word
another line without it
test line 3 with two test words
test line 4

Theo mặc định, greptrả về mỗi dòng có chứa cụm từ tìm kiếm:

$ grep test test

test line 1
test line 2
test line 3 with two test words
test line 4

Truyền --colortham số grepsẽ làm cho nó làm nổi bật phần của dòng khớp với biểu thức tìm kiếm, nhưng nó vẫn chỉ trả về các dòng có chứa biểu thức. Có cách nào để grepxuất ra mọi dòng trong tệp nguồn, nhưng làm nổi bật các kết quả khớp?

Bản hack khủng khiếp hiện tại của tôi để thực hiện điều này (ít nhất là trên các tệp không có hơn 10000 dòng liên tiếp không có kết quả trùng khớp) là:

$ grep -B 9999 -A 9999 test test

Ảnh chụp màn hình của hai lệnh

Nếu grepkhông thể thực hiện được điều này, có công cụ dòng lệnh nào khác cung cấp chức năng tương tự không? Tôi đã loay hoay ack, nhưng dường như cũng không có lựa chọn nào cho nó.


1
Trang web chéo có thể trùng lặp của: stackoverflow.com/questions/981601/ Tên Câu trả lời hàng đầu là giống nhau trên cả hai.
Ciro Santilli 心 心 事件

1
Bạn có thể sử dụng -C 9999thay cho. -A 9999 -B 9999Tôi luôn luôn làm:grep -C 9999 pattern file
neo

Câu trả lời:


184
grep --color -E "test|$" yourfile

Những gì chúng tôi đang làm ở đây là khớp với $mẫu và mẫu thử, rõ ràng là $không có gì để làm mờ nên chỉ có mẫu thử có màu. Chỉ -Ecần bật kết hợp regex mở rộng.

Bạn có thể tạo một hàm từ nó dễ dàng như thế này:

highlight () { grep --color -E "$1|$" "${@:1}" ; }

14
Thật là tuyệt vời!
gvkv

3
Và như là một chức năng : highlight () { grep --color -E "$1|$" $2 ; }. Cách sử dụng:highlight test yourfile
Stefan Lasiewski

2
@StefanLasiewski: "$2"cũng nên được trích dẫn.
Dennis Williamson

6
Tốt hơn có thể là: highlight () { grep --color -E "$1|$" "$@" }cho phép các tệp có khoảng trắng trong tên nhiều tệp.
Mike DeSimone

15
@MikeDeSimone - Nhưng điều đó cũng sẽ có "$1"trong các tập tin. Sử dụnghighlight () { grep --color -E "$1|$" "${@:1}" }
Chris Down

40
ack --passthru --color string file

đối với Ubuntu và Debian, hãy sử dụng ack-grep thay vì ack

ack-grep --passthru --color string file

1
Ồ, đó là khá rõ ràng trong trang người đàn ông; Tôi bị mù. Cảm ơn
Michael Mrozek

mô hình cho grap có thể được chỉ định rõ ràng với --regexp string; tương đương ack / ack-grep là--match string
Rhubbarb

Để mô phỏng ack --passthruvới perl:grep_passthrough () { ! perl -ne "print; \$e ||= /$@/; END{{exit \$e}}"; }
Lucas Cimon

ack --passthrucũng hoạt động trên các luồng! Ví dụ:ifconfig | ack --passthru inet
honkaboy

13

Một cách khác để làm điều này đúng cáchportably với grep(ngoài cách sử dụng hai regexes với luân phiên như trong câu trả lời được chấp nhận) là thông qua mô hình null (và chuỗi tương ứng null).
Nó sẽ hoạt động tốt như nhau với cả hai -E-Fchuyển đổi kể từ, theo tiêu chuẩn :

-E
    Match using extended regular expressions. 
    [...] A null ERE shall match every line.

-F
    Match using fixed strings.
    [...] A null string shall match every line.

Vì vậy, nó chỉ đơn giản là một vấn đề chạy

grep -E -e '' -e 'pattern' infile

và tương ứng

grep -F -e '' -e 'string' infile

1
Hoặc chỉ grep -F -e '' -e 'string'.
Stéphane Chazelas

Nó hoạt động với tôi với GNU grep 2.25, busybox grep và công cụ gia truyền.
Stéphane Chazelas

OK, xấu của tôi, seq 3 | grep -F -e '' -e 2chỉ xuất 2 trong 2,27 (và 2,26, nhưng không phải 2,25, và không phải trong đầu git). Chỉ với -F(không phải không có hoặc có -E). IOW, chỉ có 2,26 và 2,27 dường như có lỗi và chỉ với -F.
Stéphane Chazelas

Lưu ý rằng seq 3 | grep -F -e '' -e '' -e 2 dường như cũng hoạt động tốt với 2.27
Stéphane Chazelas

1
Phương pháp được đưa ra trong câu trả lời này là đơn giản, chính xác và có vẻ khá nhanh . Như bạn nói , nó hoạt động tự động -F, giảm bớt sự cần thiết phải lo lắng về những gì các nhân vật xuất hiện trong string. Bạn có thể muốn đề cập đến --color; vì câu trả lời này nổi lên trên trang (khi được xem bằng phiếu), nhiều người có thể sẽ đọc nó trước các câu trả lời khác.
Eliah Kagan

11

Tôi có chức năng sau đây mà tôi sử dụng cho những thứ đó:

highlight () {
    perl -pe "s/$1/\e[1;31;43m$&\e[0m/g"
}

Bên trong nó trông có vẻ xấu xí, nó đẹp và dễ sử dụng, như vậy:

cat some_file.txt | highlight some_word

hoặc, cho một ví dụ thực tế hơn một chút:

tail -f console.log | highlight ERROR

Bạn có thể thay đổi màu sắc thành bất cứ thứ gì bạn thích (có thể khó với grep - tôi không chắc chắn) bằng cách thay đổi 13143(sau \e[) thành các giá trị khác nhau. Các để sử dụng là tất cả qua nơi này , nhưng đây là giới thiệu nhanh về: 1 bolds văn bản, 31làm cho nó màu đỏ, và 43đưa ra một nền màu vàng. 32hoặc 33sẽ là màu sắc khác nhau, và 44hoặc 45sẽ là nền tảng khác nhau: bạn có ý tưởng. Bạn thậm chí có thể làm cho nó nhấp nháy (với a 5) nếu bạn quá nghiêng.

Điều này không sử dụng bất kỳ mô-đun Perl đặc biệt nào và Perl gần như có mặt ở khắp mọi nơi, vì vậy tôi hy vọng nó sẽ hoạt động ở mọi nơi. Giải pháp grep rất thông minh, nhưng công tắc --color trên grep không có sẵn ở mọi nơi. Chẳng hạn, tôi vừa thử giải pháp này trên hộp Solaris đang chạy bash và một ksh khác đang chạy và máy Mac OS X cục bộ của tôi chạy zsh. Tất cả đều hoạt động tốt. Solaris nghẹn lời về grep --colorgiải pháp, tuy nhiên.

Ngoài ra, ack rất tuyệt và tôi giới thiệu nó cho bất kỳ ai chưa phát hiện ra nó, nhưng tôi đã gặp một số vấn đề khi cài đặt nó trên một vài trong số nhiều máy chủ mà tôi làm việc. (Tôi quên tại sao: Tôi nghĩ có liên quan đến các mô-đun Perl mà nó yêu cầu.)

Vì tôi không nghĩ rằng tôi đã từng làm việc với một hộp Unix chưa cài đặt Perl (ngoại trừ các hệ thống kiểu nhúng, bộ định tuyến Linksys, v.v.) Tôi nói rằng đây là một giải pháp có thể sử dụng phổ biến .


3

Thay vì sử dụng Grep, bạn có thể sử dụng Ít hơn:

less file

Tìm kiếm như thế này: /pattern Enter

Điều này sẽ:

  1. cuộn đến dòng khớp đầu tiên
  2. đầu ra mỗi dòng bắt đầu từ đó
  3. làm nổi bật tất cả các trận đấu

Để cuộn đến dòng phù hợp tiếp theo: n

Để cuộn đến dòng phù hợp trước đó: N

Để chuyển đổi tô sáng: Esc u

Ngoài ra, bạn có thể thay đổi màu tô sáng nếu bạn thích.


2

Bạn co thể thử:

perl -MTERM::ANSIColor -nle '/pattern/ ? print colored($_, 'color') : print' test

Tuy nhiên, không dễ mang theo, và ngay cả khi Perl được cài đặt, bạn có thể cần phải tải xuống một mô-đun khác. Ngoài ra, nó sẽ tô màu toàn bộ dòng, không chỉ từ tìm kiếm.


2

ripgrep

Sử dụng ripgrepvới --passthrutham số của nó :

rg --passthru pattern file.txt

Đây là một trong những công cụ grepping nhanh nhất , vì nó được xây dựng trên công cụ regex của Rust , sử dụng automata hữu hạn, SIMD và tối ưu hóa theo nghĩa đen tích cực để giúp tìm kiếm rất nhanh.

--passthru - In cả hai dòng phù hợp và không phù hợp.

Một cách khác để đạt được hiệu ứng tương tự là sửa đổi mẫu của bạn để khớp với chuỗi trống. Ví dụ: nếu bạn đang tìm kiếm bằng cách sử dụng rg foothì rg "^|foo"thay vào đó sẽ phát ra mọi dòng trong mỗi tệp được tìm kiếm, nhưng chỉ các lần xuất hiện của foo sẽ được tô sáng. Cờ này cho phép hành vi tương tự mà không cần phải sửa đổi mẫu.


1

Có một cách dễ dàng hơn nhiều để làm điều này cho GNU grep nhưng tôi không nghĩ nó có thể mang theo được (tức là BSD grep):

Trong một đường ống:

cat <file> | grep --color=always -z <query>

Trên một tập tin:

grep --color=always -z <query> <file>

Tín dụng đi đến câu trả lời của Cyrus ở đây .


1
Đây không phải là một câu trả lời tốt như bạn (và Cyrus) nghĩ. Nó có tác dụng coi toàn bộ tập tin là một dòng duy nhất. Do đó, (1) nếu tệp rất lớn, có thể có khả năng hết bộ nhớ và (2) nếu tệp không chứa mẫu nào cả , thì sẽ không có gì xuất ra. Và bạn đã đúng; nó không phải là phổ biến (Nhưng sau đó, một lần nữa, --colorcũng không phải là tiêu chuẩn .)
G-Man

Phiên bản grep này được hỗ trợ trên? Trên grep 2.5.4, -z dường như không có sẵn ...
Alex

1

Không có câu trả lời nào được đưa ra cho đến nay không cung cấp một giải pháp di động .

Đây là một di 1 chức năng vỏ tôi đã được đăng trong một khép kín như câu hỏi trùng lặp mà không yêu cầu các công cụ tiêu chuẩn không hoặc phần mở rộng tiêu chuẩn không cung cấp perl, ack, ggrep, gsed, bashvà thích nhưng chỉ cần một vỏ POSIX và các tiện ích bắt buộc POSIX sedprintf:

grepc()
{
  pattern=$1
  shift
  esc=$(printf "\033")
  sed 's"'"$pattern"'"'$esc'[32m&'$esc'[0m"g' "$@"
}

Bạn có thể sử dụng nó theo cách đó:

grepc string_to_search [file ...]

Màu sắc nổi bật có thể được điều chỉnh bằng cách sử dụng một trong các mã này trong đối số lệnh sed (32m có màu xanh lá cây ở đây):

30m black
31m red
33m yellow
34m blue
35m magenta
36m cyan
37m white
7m reverse video

1 Miễn là thiết bị đầu cuối của bạn hỗ trợ các chuỗi thoát màu ANSI.


0

Một sedphiên bản, hoạt động trên cả bashash.

#highlight
hsed(){
    local pattern="$1"
    shift
    local r=`echo -e '\e'[31m`
    local c=`echo -e '\e'[0m`
    sed "s:${pattern//:/\:}:$r\0$c:g" "$@"
}

0

OP đã yêu cầu grepvà đó là những gì tôi KIẾN NGHỊ ; nhưng sau khi cố gắng hết sức để giải quyết vấn đề với sed, đối với bản ghi, đây là một giải pháp đơn giản với nó:

sed $'s/main/\E[31m&\E[0m/g' testt.c

hoặc là

cat testt.c | sed $'s/main/\E[31m&\E[0m/g'

Sẽ sơn mainmàu đỏ.

  • \E[31m : trình tự bắt đầu màu đỏ
  • \E[0m : đánh dấu màu đã hoàn thành
  • & : mẫu phù hợp
  • /g : tất cả các từ trong một dòng, không chỉ đầu tiên
  • $'string' là chuỗi bash với các ký tự thoát được giải thích

Về grep , nó cũng hoạt động bằng cách sử dụng ^(bắt đầu dòng) thay vì $(cuối dòng). Thí dụ:

egrep "^|main" testt.c

Và chỉ để hiển thị bí danh điên rồ này mà tôi KHÔNG GIỚI THIỆU , bạn thậm chí có thể để các trích dẫn mở:

alias h='egrep -e"^|'
h main" testt.c
cat testt.c | h main"

tất cả công việc! :) Đừng lo lắng nếu bạn quên đóng trích dẫn, bash sẽ nhớ bạn với "ký tự dòng tiếp tục".

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.