วิธีการ grep บรรทัดที่ระบุ _and_ บรรทัดแรกของไฟล์?


76

สมมติว่าเป็น grep อย่างง่ายเช่น:

$ psa aux | grep someApp
1000     11634 51.2  0.1  32824  9112 pts/1    SN+  13:24   7:49 someApp

สิ่งนี้จัดเตรียมข้อมูลจำนวนมาก แต่เนื่องจากบรรทัดแรกของคำสั่ง ps หายไปจึงไม่มีบริบทสำหรับข้อมูล ฉันต้องการให้แสดงบรรทัดแรกของ ps ด้วยเช่นกัน:

$ psa aux | someMagic someApp
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
1000     11634 51.2  0.1  32824  9112 pts/1    SN+  13:24   7:49 someApp

แน่นอนฉันสามารถเพิ่ม regex เพื่อ grep เฉพาะสำหรับ ps:

$ ps aux | grep -E "COMMAND|someApp"

อย่างไรก็ตามฉันต้องการโซลูชันทั่วไปมากกว่าเนื่องจากมีกรณีอื่น ๆ ที่ฉันต้องการมีบรรทัดแรกเช่นกัน

ดูเหมือนว่านี้จะเป็นกรณีการใช้งานที่ดีสำหรับการเป็น "stdmeta" ไฟล์อธิบาย


9
ความซับซ้อนที่ต้องการโดยคำตอบเหล่านี้แสดงให้เห็นว่าปรัชญา Unix ของ "ทำสิ่งใดสิ่งหนึ่งและทำได้ดี" บางครั้งก็ล้มเหลวเราเมื่อวัดจากการใช้งานของหลา: รู้คำสั่งทั้งหมดเหล่านี้ดีพอที่จะใช้พวกเขากับปัญหาทั่วไปนี้ และยังคงเห็นป้ายชื่อคอลัมน์) แสดงข้อเสียของวิธีการ: บางครั้งสิ่งที่ไม่เข้ากันอย่างหมดจด นี่คือเหตุผลว่าทำไมเครื่องมือเช่นackนั้นมีประโยชน์มากและทำไมความนิยมในperlอดีตจึงพุ่งสูงขึ้นไปsedอีกawk: มันเป็นสิ่งสำคัญที่ชิ้นส่วนต่างๆจะต้องรวมเข้าด้วยกัน
iconoclast

3
แน่นอนสำหรับตัวอย่างนี้คุณสามารถใช้-Cอาร์กิวเมนต์เพื่อpsและคุณไม่จำเป็นต้องไพพ์ให้เป็น grep เช่นps u -C someAppหรือแม้กระทั่งps u -C app1 -C app2 -C app3
cas

1
@iconoclast: แน่นอนว่าโซลูชัน Unixy จะเป็นเครื่องมือที่สามารถทำหลายบรรทัดหลายบรรทัดในการกรองผ่านชุดตัวกรองที่แตกต่างกัน Kinda รุ่นทั่วไปของps aux | { head -1; grep foo; }กล่าวโดย @Nahuel Fouilleul ด้านล่าง (ของเขาน่าจะเป็นทางออกเดียวที่ฉันจะสามารถเรียกคืนในจุดที่ถ้าจำเป็น)
โกหกไรอัน

@iconoclast: การขาดประสบการณ์และความรู้เกี่ยวกับเครื่องมือสิ่งที่เครื่องมือทำดีจริง ๆ ดูเหมือนจะไร้ประโยชน์อย่างสิ้นเชิง การรู้คำสั่งเป็นอย่างดีไม่ว่าจะอยู่ที่ไหนในสนามหลาของการใช้งานมันอยู่ในแท่งไม้ของการอ่านคู่มือที่ดีและการปฏิบัติ เครื่องมือเหล่านี้มีมานานหลายทศวรรษ พวกเขาทำงานและเข้ากันได้ดีมาก (และเรียบร้อย)
ЯрославРахматуллин

@ ЯрославРахматуллин: ฉันคิดว่าคุณอาจเข้าใจผิดอย่างสมบูรณ์ในสิ่งที่ฉันพูด (อาจเป็นเพราะภาษาอังกฤษไม่ใช่ภาษาแรกของคุณ?) "การใช้งาน" เกี่ยวข้องกับ UX ("ประสบการณ์ผู้ใช้") ไม่ใช่ยูทิลิตี้ (หรือ "ประโยชน์") ชี้ให้เห็นว่าเมื่อการดำเนินการอย่างง่ายเป็นสิ่งที่ซับซ้อนนี้มันเจ็บการใช้งานไม่เหมือนกับการบอกว่าเครื่องมือไร้ประโยชน์ ค่อนข้างชัดเจนว่าพวกเขาไม่ได้ไร้ประโยชน์ ไม่มีใครในใจถูกต้องจะบอกว่าพวกเขาไร้ประโยชน์
iconoclast

คำตอบ:


67

วิธีที่ดี

โดยปกติคุณไม่สามารถใช้ grep ได้ แต่คุณสามารถใช้เครื่องมืออื่น ๆ ได้ AWK ถูกกล่าวถึงแล้ว แต่คุณสามารถใช้sedเช่นนี้:

sed -e '1p' -e '/youpattern/!d'

มันทำงานอย่างไร:

  1. ยูทิลิตี้ Sed ทำงานบนแต่ละบรรทัดแยกกันโดยรันคำสั่งที่ระบุในแต่ละบรรทัด คุณสามารถมีหลายคำสั่งโดยระบุหลาย-eตัวเลือก เราสามารถผนวกแต่ละคำสั่งด้วยพารามิเตอร์ช่วงที่ระบุว่าควรใช้คำสั่งนี้กับบรรทัดที่ระบุหรือไม่

  2. "1p" เป็นคำสั่งแรก มันใช้pคำสั่งซึ่งปกติจะพิมพ์ทุกบรรทัด แต่เราเติมมันด้วยค่าตัวเลขที่ระบุช่วงที่ควรนำไปใช้ ที่นี่เราใช้1ซึ่งหมายถึงบรรทัดแรก หากคุณต้องการพิมพ์บรรทัดเพิ่มเติมคุณสามารถใช้x,ypตำแหน่งที่xจะพิมพ์บรรทัดแรกเป็นบรรทัดyสุดท้ายในการพิมพ์ ตัวอย่างเช่นการพิมพ์ 3 บรรทัดแรกคุณจะใช้1,3p

  3. คำสั่งถัดไปdซึ่งโดยปกติจะลบบรรทัดทั้งหมดจากบัฟเฟอร์ ก่อนหน้าคำสั่งนี้เราใส่yourpatternระหว่างสอง/ตัวละคร นี่คือวิธีอื่น (ก่อนอื่นคือระบุบรรทัดที่เราทำด้วยpคำสั่ง) ของการกำหนดแอดเดรสบรรทัดที่คำสั่งควรรันอยู่ ซึ่งหมายความว่าคำสั่งจะใช้งานได้กับบรรทัดที่ตรงกันyourpatternเท่านั้น ยกเว้นว่าเราจะใช้!ตัวอักษรก่อนdคำสั่งซึ่งกลับเหตุผลของมัน ดังนั้นตอนนี้มันจะลบบรรทัดทั้งหมดที่ไม่ตรงกับรูปแบบที่ระบุ

  4. ในตอนท้าย sed จะพิมพ์บรรทัดทั้งหมดที่เหลืออยู่ในบัฟเฟอร์ แต่เราลบบรรทัดที่ไม่ตรงจากบัฟเฟอร์ดังนั้นเฉพาะบรรทัดที่ตรงกันเท่านั้นที่จะถูกพิมพ์

เพื่อสรุป: เราพิมพ์บรรทัดที่ 1 จากนั้นเราจะลบบรรทัดทั้งหมดที่ไม่ตรงกับรูปแบบของเราออกจากอินพุต ส่วนที่เหลือของสายจะถูกพิมพ์ (เส้นเท่านั้นดังนั้นที่ทำตรงกับรูปแบบ)

ปัญหาบรรทัดแรก

ดังกล่าวในความคิดเห็นมีปัญหากับวิธีนี้ หากรูปแบบที่ระบุตรงกับบรรทัดแรกก็จะถูกพิมพ์สองครั้ง (ครั้งเดียวโดยpคำสั่งและอีกครั้งเพราะการแข่งขัน) เราสามารถหลีกเลี่ยงปัญหานี้ได้สองวิธี:

  1. การเพิ่มคำสั่งหลัง1d 1pดังที่ฉันได้กล่าวไปแล้วdคำสั่งจะลบบรรทัดออกจากบัฟเฟอร์และเราระบุช่วงเป็นหมายเลข 1 ซึ่งหมายความว่ามันจะลบบรรทัดที่ 1 เท่านั้น ดังนั้นคำสั่งจะเป็นsed -e '1p' -e '1d' -e '/youpattern/!d'

  2. การใช้คำสั่งแทน1b 1pมันเป็นเคล็ดลับ bคำสั่งอนุญาตให้เราข้ามไปยังคำสั่งอื่นที่ระบุโดยเลเบล แต่ถ้าไม่ได้ระบุป้ายกำกับนี้ (ตามตัวอย่างของเรา) เพียงแค่ข้ามไปยังจุดสิ้นสุดของคำสั่งให้ละเว้นคำสั่งที่เหลือสำหรับบรรทัดของเรา ดังนั้นในกรณีของเราdคำสั่งสุดท้ายจะไม่ลบบรรทัดนี้ออกจากบัฟเฟอร์

ตัวอย่างเต็มรูปแบบ:

ps aux | sed -e '1b' -e '/syslog/!d'

ใช้เครื่องหมายอัฒภาค

sedการใช้งานบางอย่างสามารถช่วยคุณประหยัดการพิมพ์โดยใช้อัฒภาคเพื่อแยกคำสั่งแทนที่จะใช้หลาย-eตัวเลือก ดังนั้นหากคุณไม่สนใจที่จะพกพาคำสั่งจะเป็นps aux | sed '1b;/syslog/!d'เช่นนั้น มันทำงานอย่างน้อยในGNU sedและbusyboxการใช้งาน

ทางบ้า

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

ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog'

มันทำงานอย่างไร

  1. ก่อนอื่นเราใช้-nตัวเลือกเพื่อเพิ่มหมายเลขบรรทัดก่อนแต่ละบรรทัด เราต้องการที่จะนับจำนวนบรรทัดทั้งหมดที่เราจับคู่ไว้.*- อะไรก็ได้แม้แต่บรรทัดที่ว่างเปล่า ตามที่แนะนำในความคิดเห็นเราสามารถจับคู่ '^' ผลลัพธ์เหมือนกัน

  2. จากนั้นเราใช้นิพจน์ทั่วไปเพิ่มเติมเพื่อให้เราสามารถใช้\|อักขระพิเศษซึ่งทำงานเป็น OR ดังนั้นเราจะจับคู่ว่าบรรทัดเริ่มต้นด้วย1:(บรรทัดแรก) หรือมีรูปแบบของเรา (ในกรณีนี้คือsyslog)

ปัญหาหมายเลขบรรทัด

ตอนนี้ปัญหาคือเราได้รับหมายเลขบรรทัดที่น่าเกลียดนี้ในผลลัพธ์ของเรา หากนี่เป็นปัญหาเราสามารถลบออกได้cutเช่นนี้

ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog' | cut -d ':' -f2-

-dตัวเลือกระบุตัวคั่น-fระบุเขตข้อมูล (หรือคอลัมน์) ที่เราต้องการพิมพ์ ดังนั้นเราจึงต้องการตัดแต่ละบรรทัดของ:ตัวละครทุกตัวและพิมพ์เฉพาะคอลัมน์ที่ 2 และคอลัมน์ถัดไปทั้งหมด สิ่งนี้จะลบคอลัมน์แรกอย่างมีประสิทธิภาพด้วยตัวคั่นและนี่คือสิ่งที่เราต้องการ


4
การกำหนดหมายเลขบรรทัดสามารถทำได้ด้วยcat -nเช่นกันและจะดูชัดเจนขึ้นเช่นเดียวกับ grep ที่ใช้ในทางที่ผิด
Alfe

1
nlไม่นับบรรทัดว่าง (แต่พิมพ์โดยไม่มีหมายเลขบรรทัด) จัดcat -nรูปแบบการกำหนดหมายเลขด้วยช่องว่างข้างหน้าgrep -n .ตัดบรรทัดว่างทั้งหมดและเพิ่มเครื่องหมายจุดคู่ ทั้งหมดมีคุณสมบัติ ... เอ้อ ... ;-) ของพวกเขา
Alfe

2
คำตอบที่ดีเป็นลายลักษณ์อักษรทางการศึกษามาก ฉันพยายามแทนที่ "Pretend" (ใกล้ถึงจุดเริ่มต้น) ด้วย "Prepend" สำหรับคุณ แต่มันต้องการการเปลี่ยนแปลงมากกว่าและฉันไม่รู้สึกอยากเปลี่ยนอึแบบสุ่มในโพสต์ของคุณดังนั้นคุณอาจต้องการแก้ไข
Bill K

2
ps aux | sed '1p;/pattern/!d'จะพิมพ์บรรทัดแรกสองครั้งถ้ามันตรงกับรูปแบบ ดีที่สุดคือการใช้คำสั่ง:b ไม่ใช่ POSIX จะกำหนดหมายเลขทุกบรรทัด (ไม่ใช่ปัญหาสำหรับเอาต์พุต ps ซึ่งไม่มีบรรทัดว่างเปล่า) ตัวเลขทุกบรรทัด ps aux | sed -e 1b -e '/pattern/!d'cat -ngrep -n '^'nl -ba -d $'\n'
Stéphane Chazelas

2
โปรดทราบว่า1b;...ไม่ใช่พกพาหรือ POSIX ไม่สามารถมีคำสั่งอื่นหลังจาก "b" ดังนั้นคุณต้องขึ้นบรรทัดใหม่หรือนิพจน์อื่น -e
Stéphane Chazelas

58

คุณรู้สึกอย่างไรเกี่ยวกับการใช้awkแทนgrep?

chopper:~> ps aux | awk 'NR == 1 || /syslogd/'
USER              PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
root               19   0.0  0.0  2518684   1160   ??  Ss   26Aug12   1:00.22 /usr/sbin/syslogd
mrb               574   0.0  0.0  2432852    696 s006  R+    8:04am   0:00.00 awk NR == 1 || /syslogd/
  • NR == 1: จำนวนบันทึก == 1; กล่าวคือ บรรทัดแรก
  • ||: หรือ:
  • /syslogd/: รูปแบบการค้นหา

มันอาจจะคุ้มค่าที่pgrepจะดูแม้ว่ามันจะมีประโยชน์มากกว่าสำหรับสคริปต์ มันจะหลีกเลี่ยงgrepคำสั่งเองไม่ให้ปรากฏในเอาต์พุต

chopper:~> pgrep -l syslogd
19 syslogd

ดีมากขอบคุณ นี่เป็นสคริปต์ที่ดีสำหรับการขยายตัวในอนาคต
dotancohen

ฉันต้องเรียนรู้ฉันบ้างไหม ดีมาก.
user606723

30
ps aux | { read line;echo "$line";grep someApp;}

แก้ไข: หลังจากความคิดเห็น

ps aux | { head -1;grep someApp;}

ฉันว่าhead -1จะอ่านอินพุตทั้งหมด แต่หลังจากทดสอบแล้วก็ใช้งานได้เช่นกัน

{ head -1;grep ok;} <<END
this is a test
this line should be ok
not this one
END

ผลลัพธ์คือ

this is a test
this line should be ok

2
นั่นคือความคิดที่สะกดออกมาโดยตรงในการทุบตี ฉันต้องการยกนิ้วให้มากกว่านี้ ฉันอาจจะใช้{ IFS='' read line; ... }ในกรณีที่ส่วนหัวเริ่มต้นด้วยช่องว่าง
Alfe

นี้ไม่ว่าโจมตีปัญหาโดยตรง ดี!
dotancohen

3
ฉันแค่ใช้head -1แทนคำสั่ง read / echo
chepner

1
มันใช้ได้กับhead -n1ทุบตีของฉัน นี่อาจเป็นการใช้งานที่เฉพาะเจาะจง หัวของฉันไม่ได้อ่านอินพุตทั้งหมดในกรณีนี้มีเพียงบรรทัดแรกเท่านั้นที่เหลือไว้ในบัฟเฟอร์อินพุต
Krzysztof Adamski

2
head -n1สั้นลง แต่ปรากฏว่า POSIX เงียบแม้จะอนุญาตให้ป้อนข้อมูลได้มากเท่าไหร่ดังนั้นอาจread line; echo $lineพกพาได้มากกว่า
chepner

14

Ps สนับสนุนตัวกรองภายใน

สมมติว่าคุณกำลังมองหากระบวนการทุบตี:

ps -C bash -f

bashจะแสดงกระบวนการทั้งหมดที่ตั้งชื่อ


ขอบคุณที่รู้ดี อย่างไรก็ตามจะไม่พบสคริปต์ที่เริ่มต้นจาก python และอื่น ๆ
dotancohen

6

ฉันมักจะส่งส่วนหัวไปยังstderr :

ps | (IFS= read -r HEADER; echo "$HEADER" >&2; cat) | grep ps

ซึ่งเพียงพอสำหรับการอ่านของมนุษย์ เช่น:

  PID TTY          TIME CMD
 4738 pts/0    00:00:00 ps

ส่วนที่อยู่ในวงเล็บอาจเป็นสคริปต์ของตัวเองสำหรับการใช้งานทั่วไป

มีความสะดวกเพิ่มขึ้นในการที่สามารถส่งออกไปป์ไลน์ (ไปยังsortอื่น ๆ ) และส่วนหัวจะยังคงอยู่ด้านบน


5

คุณสามารถใช้teeและhead:

ps aux | tee >(head -n1) | grep syslog

อย่างไรก็ตามโปรดทราบว่าตราบใดที่teeไม่สามารถเพิกเฉยต่อSIGPIPEสัญญาณ (ดูตัวอย่างเช่นการสนทนาที่นี่ ) วิธีการนี้จำเป็นต้องมีวิธีแก้ไขปัญหาที่เชื่อถือได้ วิธีแก้ปัญหาคือการละเว้นสัญญาณ SIGPIPE สิ่งนี้สามารถทำได้เช่นนี้ใน bash like shells:

trap '' PIPE    # ignore SIGPIPE
ps aux | tee >(head -n1) 2> /dev/null | grep syslog
trap - PIPE     # restore SIGPIPE handling

นอกจากนี้ยังทราบว่าเพื่อการส่งออกจะไม่รับประกัน


ฉันจะไม่พึ่งพาสิ่งนี้ในการทำงานครั้งแรกที่ฉันเรียกใช้ (zsh) จะสร้างส่วนหัวคอลัมน์ด้านล่างผลลัพธ์ grep ครั้งที่สองก็ไม่เป็นไร
Rqomey

1
ฉันไม่ได้เห็นนี้ยัง แต่วิธีหนึ่งที่จะเพิ่มความน่าเชื่อถือคือการแทรกความล่าช้าเล็กน้อยในท่อก่อน:grep | { sleep .5; cat }
Thor

2
การเพิ่มโหมดสลีปเพื่อหลีกเลี่ยงปัญหาเกิดขึ้นพร้อมกันนั้นจะเป็นการแฮก แม้ว่านี่อาจใช้งานได้ แต่มันเป็นขั้นตอนสู่ด้านมืด -1 สำหรับสิ่งนี้
Alfe

1
ฉันมีปัญหาแปลก ๆ อีกสองสามข้อในขณะที่พยายามตอบคำถามนี้ฉันตั้งคำถามเพื่อตรวจสอบ
Rqomey

นี่คือการใช้ทีน่าสนใจ แต่ฉันพบว่ามันไม่น่าเชื่อถือและมักจะพิมพ์เฉพาะบรรทัดเอาต์พุตเท่านั้น แต่ไม่ใช่บรรทัดส่วนหัว
dotancohen

4

บางทีpsคำสั่งสองคำอาจจะง่ายที่สุด

$ ps aux | head -1 && ps aux | grep someApp
USER             PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
100         3304   0.0  0.2  2466308   6476   ??  Ss    2Sep12   0:01.75 /usr/bin/someApp

2
ฉันไม่ชอบวิธีแก้ปัญหานี้เป็นหลักเนื่องจากสถานการณ์อาจเปลี่ยนไประหว่างการps auxโทรครั้งแรกและครั้งที่สอง... และหากคุณต้องการให้บรรทัดแรกคงที่ทำไมไม่สะท้อนด้วยตนเอง?
Shadur

1
การเปลี่ยนแปลงระหว่างสองสายที่ไม่ได้รับการใส่ใจในนี้สถานการณ์ ครั้งแรกจะให้พาดหัวซึ่งมักจะพอดีกับการส่งออกของที่สอง
Alfe

2
ฉันไม่เห็นว่าทำไมสิ่งนี้จึงถูกลดทอนลงแน่นอนเป็นตัวเลือกที่เหมาะสม Upvoting
dotancohen

4

คุณสามารถใช้ pidstat กับ:

pidstat -C someApp
or
pidstat -p <PID>

ตัวอย่าง:

# pidstat -C java
Linux 3.0.26-0.7-default (hostname)    09/12/12        _x86_64_

13:41:21          PID    %usr %system  %guest    %CPU   CPU  Command
13:41:21         3671    0.07    0.02    0.00    0.09     1  java

ข้อมูลเพิ่มเติม: http://linux.die.net/man/1/pidstat


ขอบคุณที่รู้ดี อย่างไรก็ตามจะไม่พบสคริปต์ที่เริ่มต้นจาก python และอื่น ๆ
dotancohen

4

ใส่ต่อไปนี้ในไฟล์. bashrc ของคุณหรือคัดลอก / วางในเชลล์ก่อนเพื่อทำการทดสอบ

function psls { 
ps aux|head -1 && ps aux|grep "$1"|grep -v grep;
}

การใช้งาน: psls [grep pattern]

$ psls someApp
USER             PID  %CPU %MEM      VSZ    RSS   TT  STAT STARTED      TIME COMMAND
root              21   0.0  0.0  2467312   1116   ??  Ss   Tue07PM   0:00.17 /sbin/someApp

ตรวจสอบให้แน่ใจว่าได้จัดหา. bashrc ของคุณ (หรือ. bash_profile หากคุณใส่ไว้ที่นั่น):

source ~/.bashrc

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


1
เยี่ยมมากฉันใช้ฟังก์ชั่นแบบนั้นมาหลายปีแล้ว ฉันเรียกรุ่นของฉันpslซึ่งจะโทรpsและgrepหนึ่งครั้งเท่านั้น(และไม่จำเป็นhead)
Adam Katz

3

จัดเรียง แต่ให้บรรทัดส่วนหัวอยู่ด้านบน

# print the header (the first line of input)
# and then run the specified command on the body (the rest of the input)
# use it in a pipeline, e.g. ps | body grep somepattern
body() {
    IFS= read -r header
    printf '%s\n' "$header"
    "$@"
}

และใช้มันเช่นนี้

$ ps aux | body grep someApp
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
1000     11634 51.2  0.1  32824  9112 pts/1    SN+  13:24   7:49 someApp

ขอบคุณคำตอบบางคำเหล่านี้พูดถึงกรณีทั่วไปของคำถามนี้ ที่สมบูรณ์แบบ!
dotancohen

3

ขอบคุณ Janis Papanagnou ส่วนใหญ่ใน comp.unix.shell ฉันใช้ฟังก์ชั่นต่อไปนี้:

function grep1 {
    IFS= read -r header && printf "%s\n" "$header"; grep "$@"
}

สิ่งนี้มีข้อดีหลายประการ:

  • ทำงานร่วมกับ bash, zsh และ ksh ได้
  • เป็นการแทนที่แบบแทนที่สำหรับ grep ดังนั้นคุณสามารถใช้แฟล็กใดก็ได้ที่คุณต้องการต่อไป: -iสำหรับการจับคู่แบบตัวพิมพ์เล็กและตัวพิมพ์ใหญ่-Eสำหรับการขยายเพิ่มเติม ฯลฯ
  • ให้รหัสทางออกเดียวกับ grep เสมอในกรณีที่คุณต้องการกำหนดโปรแกรมโดยอัตโนมัติว่ามีการจับคู่บรรทัดใด ๆ หรือไม่
  • พิมพ์ไม่มีอะไรเลยถ้าอินพุตว่างเปล่า

ตัวอย่างการใช้งาน:

$ ps -rcA | grep1 databases
  PID TTY           TIME CMD

$ ps -rcA | grep1 -i databases
  PID TTY           TIME CMD
62891 ??         0:00.33 com.apple.WebKit.Databases

2

อีกวิธีด้วยgnu ed:

ed -s '!ps aux' <<< $'2,$v/PATTERN/d\n,p\nq\n'

หรือหากเชลล์รองรับการทดแทนกระบวนการ:

printf '%s\n' '2,$v/PATTERN/d' ,p q | ed -s <(ps aux)

นั่นคือ:

2,$v/PATTERN/d  - remove all lines not matching pattern (ignore the header)
,p              - print the remaining lines
q               - quit

พกพาได้มากกว่าโดยไม่มีgnu '!' หรือทดแทนเปลือก - ใช้เฉพาะedในตัวrเพื่อrส่งออกps auxไปยังบัฟเฟอร์แล้วลบบรรทัดที่ไม่ตรงใน2,$ช่วงและพิมพ์ผลลัพธ์:

printf '%s\n' 'r !ps aux' '2,$v/PATTERN/d' ,p q | ed -s

และเนื่องจากsedคำสั่งในเอาต์พุตคำตอบที่ยอมรับยังมีการจับคู่บรรทัดด้วยตัวเองsedที่สนับสนุน-f-และเชลล์ที่รองรับการทดแทนกระบวนการฉันจะรัน:

printf '%s\n' '2,${' '/PATTERN/!d' '}' | sed -f - <(ps aux)

ซึ่งค่อนข้างสวยทำเช่นเดียวกับedคำสั่งก่อนหน้า


1

วิธี Perl:

ps aux | perl -ne 'print if /pattern/ || $.==1'

อ่านง่ายกว่าsedเร็วกว่าไม่มีความเสี่ยงในการเลือกสายที่ไม่ต้องการ



0

หากนั่นเป็นเพียงกระบวนการ grepping ที่มีส่วนหัวแบบเต็มฉันจะขยายข้อเสนอแนะของ @ mrb:

$ ps -f -p $(pgrep bash)
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
nasha     2810  2771  0  2014 pts/6    Ss+    0:00 bash
...

pgrep bash | xargs ps -fpจะได้รับผลลัพธ์เดียวกัน แต่ไม่มีการแบ่งย่อย หากจำเป็นต้องทำการฟอร์แมตอื่น:

$ pgrep bash | xargs ps fo uid,pid,stime,cmd -p
  UID   PID STIME CMD
    0  3599  2014 -bash
 1000  3286  2014 /bin/bash
 ...

-2

หากคุณรู้หมายเลขบรรทัดที่แน่นอนมันเป็นเรื่องง่ายด้วย Perl! หากคุณต้องการรับบรรทัด 1 และ 5 จากไฟล์ให้พูด / etc / passwd:

perl -e 'while(<>){if(++$l~~[1,5]){print}}' < /etc/passwd

หากคุณต้องการรับสายอื่นเช่นกันเพียงเพิ่มหมายเลขลงในอาเรย์


1
ขอขอบคุณ. ตาม OP ฉันรู้ข้อความบางส่วนในบรรทัด แต่ไม่ใช่หมายเลขบรรทัด
dotancohen

สิ่งนี้ปรากฏขึ้นเป็นคำตอบของ Google เมื่อมองหากรณีการใช้งานที่เกี่ยวข้องกับ OP อย่างใกล้ชิดดังนั้นอย่าลืมที่นี่
Dagelf

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

มีคำถามเช่นนี้ แต่พวกเขาไม่ได้ปรากฏขึ้นบน Google
Dagelf

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