โน้มน้าวให้ grep ส่งออกทุกบรรทัดไม่ใช่เฉพาะกับการแข่งขัน


121

ว่าฉันมีไฟล์ต่อไปนี้:

$ 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

ตามค่าเริ่มต้นให้grepส่งคืนแต่ละบรรทัดที่มีคำค้นหา:

$ grep test test

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

การส่งผ่าน--colorพารามิเตอร์เพื่อgrepให้ไฮไลต์ส่วนของบรรทัดที่ตรงกับนิพจน์การค้นหา แต่ก็ยังส่งคืนเฉพาะบรรทัดที่มีนิพจน์เท่านั้น มีวิธีการgrepส่งออกทุกบรรทัดในไฟล์ต้นฉบับ แต่เน้นการแข่งขันหรือไม่

แฮ็คที่แย่มากในปัจจุบันของฉันที่จะทำสิ่งนี้ให้สำเร็จ (อย่างน้อยก็ในไฟล์ที่ไม่มี 10,000+ บรรทัดติดต่อกันโดยที่ไม่ตรงกัน) คือ:

$ grep -B 9999 -A 9999 test test

สกรีนช็อตของสองคำสั่ง

หากgrepไม่สามารถทำสิ่งนี้ได้จะมีเครื่องมือบรรทัดคำสั่งอื่นที่มีฟังก์ชันการทำงานเดียวกันหรือไม่ ฉันเล่นซอackแต่ดูเหมือนจะไม่มีตัวเลือกสำหรับมัน


1
ไซต์ข้ามที่เป็นไปได้ซ้ำซ้อนกับ: stackoverflow.com/questions/981601/…คำตอบยอดนิยมเหมือนกันทั้งคู่
Ciro Santilli 新疆改造中心法轮功六四事件

1
คุณสามารถใช้-C 9999แทน-A 9999 -B 9999. ฉันทำเสมอ:grep -C 9999 pattern file
ใหม่

คำตอบ:


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

สิ่งที่เราทำที่นี่คือการจับคู่กับ$รูปแบบและรูปแบบการทดสอบเห็นได้ชัดว่า$ไม่มีอะไรที่จะ colourize ดังนั้นเฉพาะรูปแบบการทดสอบที่ได้รับสี -Eเพียงแค่เปิดการจับคู่ regex ขยาย

คุณสามารถสร้างฟังก์ชั่นได้ง่ายเช่นนี้:

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

14
นั่นมันแย่มาก!
gvkv

3
highlight () { grep --color -E "$1|$" $2 ; }และในขณะที่ฟังก์ชั่น: การใช้งาน:highlight test yourfile
Stefan Lasiewski

2
@StefanLasiewski: "$2"ควรอ้างอิงด้วย
Dennis Williamson

6
อาจดีกว่า: highlight () { grep --color -E "$1|$" "$@" }ซึ่งอนุญาตให้มีไฟล์ที่มีช่องว่างในชื่อและหลายไฟล์
Mike DeSimone

15
@MikeDeSimone - แต่นั่นจะมี"$1"ในไฟล์ด้วย ใช้highlight () { grep --color -E "$1|$" "${@:1}" }
Chris Down

39
ack --passthru --color string file

สำหรับ Ubuntu และ Debian ให้ใช้ ack-grep แทน ack

ack-grep --passthru --color string file

1
โอ้เห็นได้ชัดในหน้าคน ฉันตาบอด. ขอบคุณ
Michael Mrozek

รูปแบบสำหรับ grap อาจระบุอย่างชัดเจนด้วย--regexp string; ack / ack-grep คือ--match string
Rhubbarb

เพื่อจำลองack --passthruด้วย perl:grep_passthrough () { ! perl -ne "print; \$e ||= /$@/; END{{exit \$e}}"; }
Lucas Cimon

ack --passthruยังใช้งานได้กับสตรีม! ตัวอย่างเช่นifconfig | ack --passthru inet
honkaboy

12

อีกวิธีในการทำเช่นนี้อย่างถูกต้องและพกพาด้วยgrep(นอกเหนือจากการใช้สอง regexes กับการสลับในคำตอบที่ยอมรับ) คือผ่านรูปแบบโมฆะ (และสตริงโมฆะตามลำดับ)
มันควรจะทำงานได้ดีกับทั้งสอง-Eและ-Fสวิตช์ตั้งแต่, ตามมาตรฐาน :

-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.

ดังนั้นมันจึงเป็นเรื่องของการวิ่ง

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

และตามลำดับ

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

1
grep -F -e '' -e 'string'หรือเพียงแค่
Stéphane Chazelas

มันใช้งานได้สำหรับฉันกับ GNU grep 2.25, grep busybox และเครื่องมือมรดกตกทอด
Stéphane Chazelas

ตกลงฉันไม่ดีseq 3 | grep -F -e '' -e 2เอาท์พุทเพียง 2 ใน 2.27 (และ 2.26 แต่ไม่ใช่ 2.25 และไม่อยู่ในหัวคอมไพล์) เฉพาะที่มี-F(ไม่ใช่หรือไม่มี -E) IOW เพียง 2.26 และ 2.27 เท่านั้นที่มีข้อบกพร่องและมีเพียง -F
Stéphane Chazelas

โปรดทราบว่าseq 3 | grep -F -e '' -e '' -e 2 ดูเหมือนว่าจะทำงานได้ดีกับ 2.27
Stéphane Chazelas

1
วิธีการที่กำหนดในคำตอบนี้เป็นเรื่องง่ายที่ถูกต้องและดูเหมือนว่าค่อนข้างเร็ว ในขณะที่คุณบอกว่ามันทำงานโดยอัตโนมัติด้วยพระอัจฉริยภาพความจำเป็นที่จะต้องกังวลเกี่ยวกับสิ่งที่ตัวละครที่ปรากฏใน-F stringคุณอาจต้องการพูดถึง--color; เมื่อคำตอบนี้ลอยขึ้นบนหน้า (เมื่อดูจากการโหวต) ผู้คนจำนวนมากอาจจบลงด้วยการอ่านคำตอบก่อนคำตอบอื่น ๆ
Eliah Kagan

11

ฉันมีฟังก์ชั่นต่อไปนี้ที่ฉันใช้สำหรับสิ่งต่าง ๆ :

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

ภายในมันดูน่าเกลียดมันดีและใช้งานง่ายอย่างเช่น:

cat some_file.txt | highlight some_word

หรือสำหรับตัวอย่างจริงเพิ่มเติมอีกเล็กน้อย:

tail -f console.log | highlight ERROR

คุณสามารถเปลี่ยนสีเป็นสิ่งที่คุณชอบ (ซึ่งอาจจะยากกับ grep - ฉันไม่แน่ใจ) โดยการเปลี่ยน1และ31และ43(หลังจาก\e[) เป็นค่าที่แตกต่างกัน รหัสที่จะใช้ทั้งหมดกว่าสถานที่แต่นี่เป็นบทนำอย่างรวดเร็ว: 1 bolds ข้อความที่31ทำให้มันเป็นสีแดงและ43ทำให้พื้นหลังสีเหลือง 32หรือ33จะเป็นสีที่แตกต่างกันและ44หรือ45จะเป็นพื้นหลังที่แตกต่างกัน: คุณได้รับความคิด คุณสามารถทำให้มันกระพริบ (ด้วย5) หากคุณมีความโน้มเอียง

นี่ไม่ได้ใช้โมดูล Perl พิเศษใด ๆ และ Perl เกือบจะแพร่หลายดังนั้นฉันคาดว่ามันจะทำงานได้ทุกที่ วิธีแก้ปัญหา grep นั้นฉลาดมาก แต่สวิตช์ --color บน grep ไม่สามารถใช้ได้ทุกที่ ตัวอย่างเช่นฉันเพิ่งลองใช้วิธีแก้ปัญหานี้บนกล่อง Solaris ที่กำลังทุบตีและอีกหนึ่งตัววิ่ง ksh และเครื่อง Mac OS X ในพื้นที่ของฉันกำลังรัน zsh ทั้งหมดทำงานได้ดี โซลาริสสำลักgrep --colorวิธีการแก้ปัญหาอย่างไร

อีกทั้งแอ๊มันเจ๋งมากและฉันแนะนำให้ทุกคนที่ยังไม่ได้ค้นพบ แต่ฉันมีปัญหาบางอย่างในการติดตั้งบนเซิร์ฟเวอร์จำนวนมากที่ฉันทำงานอยู่ (ฉันลืมเหตุผล: ฉันคิดว่าเกี่ยวข้องกับโมดูล Perl ที่จำเป็น)

เนื่องจากฉันไม่คิดว่าฉันเคยทำงานกับ Unix box ที่ไม่ได้ติดตั้ง Perl (ยกเว้นระบบประเภทฝังตัว, เราเตอร์ Linksys และอื่น ๆ ) ฉันจึงบอกว่านี่เป็นโซลูชันที่ใช้งานได้ทั่วโลก .


3

แทนที่จะใช้ Grep คุณสามารถใช้ Less:

less file

ค้นหาแบบนี้: /pattern Enter

นี่จะ:

  1. เลื่อนไปที่บรรทัดแรกที่ตรงกัน
  2. เอาท์พุททุกบรรทัดเริ่มต้นจากที่นั่นบน
  3. เน้นการแข่งขันทั้งหมด

หากต้องการเลื่อนไปที่บรรทัดที่ตรงกันถัดไป: n

วิธีเลื่อนไปยังบรรทัดที่ตรงกันก่อนหน้า: N

หากต้องการสลับการไฮไลต์: Esc u

นอกจากนี้คุณสามารถเปลี่ยนสีไฮไลต์ได้ถ้าต้องการ


2

คุณสามารถลอง:

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

อย่างไรก็ตามยังไม่ค่อยพกพาได้และแม้ว่าจะติดตั้ง Perl ไว้คุณอาจต้องดาวน์โหลดโมดูลอื่น นอกจากนี้มันจะระบายสีทั้งบรรทัดไม่ใช่เฉพาะคำค้นหา


2

ripgrep

ใช้ripgrepกับ--passthruพารามิเตอร์:

rg --passthru pattern file.txt

เป็นหนึ่งในเครื่องมือ grepping ที่เร็วที่สุดเนื่องจากมันสร้างขึ้นมาจากเครื่องมือ regex ของ Rustซึ่งใช้ออโต้ไฟน์ จำกัด , SIMD และการเพิ่มประสิทธิภาพตัวอักษรที่ก้าวร้าวเพื่อให้การค้นหารวดเร็วมาก

--passthru - พิมพ์ทั้งการจับคู่และการจับคู่ที่ไม่ตรงกัน

อีกวิธีในการรับเอฟเฟกต์ที่คล้ายกันคือการปรับเปลี่ยนรูปแบบของคุณเพื่อจับคู่สตริงว่าง ตัวอย่างเช่นหากคุณกำลังค้นหาโดยใช้rg fooแล้วการใช้rg "^|foo"แทนจะปล่อยทุกบรรทัดในทุกไฟล์ที่ค้นหา แต่จะมีการเน้นเฉพาะการเกิดขึ้นของ foo เท่านั้น การตั้งค่าสถานะนี้เปิดใช้งานลักษณะการทำงานเดียวกันโดยไม่จำเป็นต้องปรับเปลี่ยนรูปแบบ


1

มีวิธีที่ง่ายกว่ามากในการทำเช่นนี้สำหรับ grep GNU แต่ฉันไม่คิดว่ามันเป็นแบบพกพา (เช่น grep BSD):

ในท่อ:

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

ในไฟล์:

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

เครดิตไปที่คำตอบของไซรัสที่นี่


1
คำตอบนี้ไม่ดีเท่าที่คุณคิด (และ Cyrus) มันมีผลต่อการรักษาไฟล์ทั้งหมดเป็นบรรทัดเดียว ดังนั้น (1) หากไฟล์มีขนาดใหญ่มากอาจมีความเป็นไปได้ที่หน่วยความจำหมดและ (2) หากไฟล์ไม่มีรูปแบบเลยก็จะไม่มีผลลัพธ์ และคุณพูดถูก; มันไม่สามารถใช้ได้ในระดับสากล (แต่จากนั้นอีกครั้ง--colorก็ไม่ได้เป็นมาตรฐานเช่นกัน)
G-Man

grep รุ่นนี้รองรับอะไรได้บ้าง? ใน grep 2.5.4, -z ไม่สามารถใช้งานได้ ...
อเล็กซ์

1

ไม่มีคำตอบใดที่ให้มาจนถึงตอนนี้ให้โซลูชั่นแบบพกพา

นี่คือแบบพกพา1ฟังก์ชั่นเปลือกผมเอาไว้แล้วในการปิดเป็นคำถามที่ซ้ำกันที่ไม่ต้องใช้เครื่องมือที่ไม่ได้มาตรฐานหรือส่วนขยายไม่ได้มาตรฐานให้กับperl, ack, ggrep, gsed, bashและชอบ แต่เพียงต้องการเปลือก POSIX และ POSIX สาธารณูปโภคบังคับsedและprintf:

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

คุณสามารถใช้วิธีนี้:

grepc string_to_search [file ...]

สีไฮไลต์สามารถปรับได้โดยใช้หนึ่งในรหัสเหล่านี้ในอาร์กิวเมนต์คำสั่ง sed (32m เป็นสีเขียวที่นี่):

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

1ตราบใดที่เทอร์มินัลของคุณรองรับลำดับการหลีกเลี่ยงสี ANSI


0

sedรุ่นทำงานได้ทั้งบนและ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 ขอgrepและนั่นคือสิ่งที่ฉันแนะนำ ; แต่หลังจากพยายามอย่างหนักในการแก้ปัญหาด้วยsedสำหรับบันทึกนี่เป็นวิธีง่ายๆในการ:

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

หรือ

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

จะทาสีmainแดง

  • \E[31m : ลำดับการเริ่มต้นสีแดง
  • \E[0m : เครื่องหมายสีเสร็จแล้ว
  • & : รูปแบบที่ตรงกัน
  • /g : ทุกคำในบรรทัดไม่ใช่แค่คำแรก
  • $'string' เป็นสตริงทุบตีที่มีการตีความตัวหนี

เกี่ยวกับgrepมันยังใช้งานได้^(เริ่มต้นบรรทัด) แทน$(จบบรรทัด) ตัวอย่าง:

egrep "^|main" testt.c

และเพื่อแสดงนามแฝงบ้าๆที่ฉันไม่แนะนำคุณสามารถปล่อยให้เปิดราคา:

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

ทำงานทั้งหมด! :) ไม่ต้องกังวลหากคุณลืมปิดการอ้างอิง bash จะจดจำคุณด้วย "อักขระต่อเนื่อง"

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.