วิธีที่ดี
โดยปกติคุณไม่สามารถใช้ grep ได้ แต่คุณสามารถใช้เครื่องมืออื่น ๆ ได้ AWK ถูกกล่าวถึงแล้ว แต่คุณสามารถใช้sedเช่นนี้:
sed -e '1p' -e '/youpattern/!d'
มันทำงานอย่างไร:
ยูทิลิตี้ Sed ทำงานบนแต่ละบรรทัดแยกกันโดยรันคำสั่งที่ระบุในแต่ละบรรทัด คุณสามารถมีหลายคำสั่งโดยระบุหลาย-eตัวเลือก เราสามารถผนวกแต่ละคำสั่งด้วยพารามิเตอร์ช่วงที่ระบุว่าควรใช้คำสั่งนี้กับบรรทัดที่ระบุหรือไม่
"1p" เป็นคำสั่งแรก มันใช้pคำสั่งซึ่งปกติจะพิมพ์ทุกบรรทัด แต่เราเติมมันด้วยค่าตัวเลขที่ระบุช่วงที่ควรนำไปใช้ ที่นี่เราใช้1ซึ่งหมายถึงบรรทัดแรก หากคุณต้องการพิมพ์บรรทัดเพิ่มเติมคุณสามารถใช้x,ypตำแหน่งที่xจะพิมพ์บรรทัดแรกเป็นบรรทัดyสุดท้ายในการพิมพ์ ตัวอย่างเช่นการพิมพ์ 3 บรรทัดแรกคุณจะใช้1,3p
คำสั่งถัดไปdซึ่งโดยปกติจะลบบรรทัดทั้งหมดจากบัฟเฟอร์ ก่อนหน้าคำสั่งนี้เราใส่yourpatternระหว่างสอง/ตัวละคร นี่คือวิธีอื่น (ก่อนอื่นคือระบุบรรทัดที่เราทำด้วยpคำสั่ง) ของการกำหนดแอดเดรสบรรทัดที่คำสั่งควรรันอยู่ ซึ่งหมายความว่าคำสั่งจะใช้งานได้กับบรรทัดที่ตรงกันyourpatternเท่านั้น ยกเว้นว่าเราจะใช้!ตัวอักษรก่อนdคำสั่งซึ่งกลับเหตุผลของมัน ดังนั้นตอนนี้มันจะลบบรรทัดทั้งหมดที่ไม่ตรงกับรูปแบบที่ระบุ
ในตอนท้าย sed จะพิมพ์บรรทัดทั้งหมดที่เหลืออยู่ในบัฟเฟอร์ แต่เราลบบรรทัดที่ไม่ตรงจากบัฟเฟอร์ดังนั้นเฉพาะบรรทัดที่ตรงกันเท่านั้นที่จะถูกพิมพ์
เพื่อสรุป: เราพิมพ์บรรทัดที่ 1 จากนั้นเราจะลบบรรทัดทั้งหมดที่ไม่ตรงกับรูปแบบของเราออกจากอินพุต ส่วนที่เหลือของสายจะถูกพิมพ์ (เส้นเท่านั้นดังนั้นที่ทำตรงกับรูปแบบ)
ปัญหาบรรทัดแรก
ดังกล่าวในความคิดเห็นมีปัญหากับวิธีนี้ หากรูปแบบที่ระบุตรงกับบรรทัดแรกก็จะถูกพิมพ์สองครั้ง (ครั้งเดียวโดยpคำสั่งและอีกครั้งเพราะการแข่งขัน) เราสามารถหลีกเลี่ยงปัญหานี้ได้สองวิธี:
การเพิ่มคำสั่งหลัง1d 1pดังที่ฉันได้กล่าวไปแล้วdคำสั่งจะลบบรรทัดออกจากบัฟเฟอร์และเราระบุช่วงเป็นหมายเลข 1 ซึ่งหมายความว่ามันจะลบบรรทัดที่ 1 เท่านั้น ดังนั้นคำสั่งจะเป็นsed -e '1p' -e '1d' -e '/youpattern/!d'
การใช้คำสั่งแทน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'
มันทำงานอย่างไร
ก่อนอื่นเราใช้-nตัวเลือกเพื่อเพิ่มหมายเลขบรรทัดก่อนแต่ละบรรทัด เราต้องการที่จะนับจำนวนบรรทัดทั้งหมดที่เราจับคู่ไว้.*- อะไรก็ได้แม้แต่บรรทัดที่ว่างเปล่า ตามที่แนะนำในความคิดเห็นเราสามารถจับคู่ '^' ผลลัพธ์เหมือนกัน
จากนั้นเราใช้นิพจน์ทั่วไปเพิ่มเติมเพื่อให้เราสามารถใช้\|อักขระพิเศษซึ่งทำงานเป็น OR ดังนั้นเราจะจับคู่ว่าบรรทัดเริ่มต้นด้วย1:(บรรทัดแรก) หรือมีรูปแบบของเรา (ในกรณีนี้คือsyslog)
ปัญหาหมายเลขบรรทัด
ตอนนี้ปัญหาคือเราได้รับหมายเลขบรรทัดที่น่าเกลียดนี้ในผลลัพธ์ของเรา หากนี่เป็นปัญหาเราสามารถลบออกได้cutเช่นนี้
ps aux | grep -n '.*' | grep -e '\(^1:\)\|syslog' | cut -d ':' -f2-
-dตัวเลือกระบุตัวคั่น-fระบุเขตข้อมูล (หรือคอลัมน์) ที่เราต้องการพิมพ์ ดังนั้นเราจึงต้องการตัดแต่ละบรรทัดของ:ตัวละครทุกตัวและพิมพ์เฉพาะคอลัมน์ที่ 2 และคอลัมน์ถัดไปทั้งหมด สิ่งนี้จะลบคอลัมน์แรกอย่างมีประสิทธิภาพด้วยตัวคั่นและนี่คือสิ่งที่เราต้องการ
ackนั้นมีประโยชน์มากและทำไมความนิยมในperlอดีตจึงพุ่งสูงขึ้นไปsedอีกawk: มันเป็นสิ่งสำคัญที่ชิ้นส่วนต่างๆจะต้องรวมเข้าด้วยกัน