วิธีการพิมพ์เนื้อหาไฟล์เฉพาะในกรณีที่บรรทัดแรกตรงกับรูปแบบที่แน่นอน?


11

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

ฉันจะตรวจสอบรูปแบบได้อย่างไร มีวิธีตรวจสอบรูปแบบและทำตามสิ่งที่ส่งออกหรือไม่ ..

แก้ไข: โปรดดูคำถามนี้: /programming/5536018/how-to-get-match-regex-pattern-using-awk-from-file

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


1
ผลลัพธ์ที่คุณคาดหวังคืออะไร รูปแบบที่คุณต้องการคืออะไร คุณลองทำอะไรไปแล้ว?
ทาชิมิ

@tachomi แก้ไขโปรดดู
Mathew

คำตอบ:


17

คุณสามารถทำได้ด้วยed:

ed -s infile <<\IN 2>/dev/null
1s/PATTERN/&/
,p
q
IN

เคล็ดลับที่นี่คือการพยายามที่จะเข้ามาแทนที่PATTERNใน1stแนวเดียวกันกับตัวเอง edจะเกิดข้อผิดพลาดหากไม่พบรูปแบบที่ระบุดังนั้น,p(พิมพ์ไฟล์ทั้งหมด) จะถูกดำเนินการ1s/PATTERN/&/ก็ต่อเมื่อสำเร็จ

หรือด้วยsed:

sed -n '1{
/PATTERN/!q
}
p' infile

สิ่งนี้จะรวมqไว้หากบรรทัดแรกไม่!ตรงกับ( ) PATTERNหรือไม่เช่นนั้นจะเป็นการpลากทุกบรรทัด
หรือตามที่Toby Speightชี้โดยมี GNU sed:

sed '1{/PATTERN/!Q}' infile

Qเหมือนกันqแต่ไม่พิมพ์พื้นที่รูปแบบ


คุณสามารถQแทนqGNU sed หรือdก่อนหน้านี้q(พกพา) เพื่อไม่ให้ใช้-nค่าสถานะและpคำสั่ง: sed '1{/PATTERN/!Q}' infileหรือsed -e '1{' -e '/PATTERN/!{' -e 'd' -e 'q' -e '}' -e '}' infileตามลำดับ
Toby Speight

dรีสตาร์ทรอบคำสั่งที่ดึงดูดฉันออกมาเสมอ! : - |
Toby Speight

ด้วย GNU คำสั่งsedแรกจะsedบ่นsed: -e expression #1, char 10: extra characters after command(เพราะp) แต่คำแนะนำedและsedคำสั่งสุดท้ายนั้นใช้ได้ผล
Skippy le Grand Gourou

หมายเหตุ: คำตอบที่ได้รับจากคำตอบนี้มีประโยชน์มากกว่าคำตอบอื่น ๆ ที่พวกเขาสามารถนำไปใช้กับไปป์
Skippy le Grand Gourou

1
@SkippyleGrandGourou - คุณได้ลองเปลี่ยนมันเป็นหนึ่งซับโดยไม่ต้องแยกคำสั่งด้วยเครื่องหมายอัฒภาค - นี้เป็นวิธีการที่เหมาะสมที่จะทำมันsed -n '1{/PATTERN/!q};p'
don_crissti

15

ด้วยหน้าอกเครื่องมือ POSIX:

{ head -n 1 | grep pattern && cat; } <file

1
{double} <sweet
mikeserv

@mikeserv: ฉันตั้งใจจะใช้มันเพื่อป้องกันไม่ให้คนใหม่สับสน แต่ Stephane ที่แก้ไขนั้นชัดเจนกว่า
cuonglm

8
 awk '/pattern/{print FILENAME}; {nextfile}' ./*.txt

จะพิมพ์ชื่อของที่ไม่ใช่ซ่อนtxtไฟล์ในไดเรกทอรีปัจจุบันที่มีเส้นตรงกับการแสดงออกปกติขยายแรกpatternกับผู้awkinplementations nextfileว่าการสนับสนุน

หากแทนที่จะพิมพ์ชื่อไฟล์คุณต้องการพิมพ์เนื้อหาไฟล์ทั้งหมดคุณสามารถทำได้:

 awk 'FNR == 1 && ! /pattern/ {nextfile}; {print}' ./*.txt

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

 awk '/pattern/{printf "%s\0", FILENAME}; {nextfile}' ./*.txt |
   xargs -r0 cat

นั่นคือใช้awkเพื่อพิมพ์รายการไฟล์ที่ตรง (คั่นด้วย 0) และใช้catเพื่อถ่ายโอนข้อมูลเนื้อหาของพวกเขา


6

หากคุณกำลังเขียนสคริปต์เชลล์คุณสามารถทำสิ่งนั้นได้

for file in ./*; do head -n 1 "$file" | grep -q 'PATTERN' && cat "$file"; done

หรือในภาษา Perl:

perl -Tlne '$f = /PATTERN/ if $. == 1; print if $f; $. = 0 if eof' ./*

@ Stéphane Chazelas: บางทีเป็นสำนวนมากกว่ามอบหมายให้close ARGV $.
cuonglm

@terdon คุณดูเหมือนโค้ดกอล์ฟทั้งหมดในหนึ่งบรรทัดไม่มีวงเล็บรอบชื่อตัวแปรและไม่สนับสนุนโครงสร้างที่สะอาด และคุณมีเครื่องหมายดอลลาร์หายไปเมื่อฉันโพสต์นั่นไม่ใช่วิธีสอนทุบตี ฉันสันนิษฐานว่าปัจจัยเหล่านั้นมาจากภูมิหลังของ perl ที่คุณดูเหมือนจะมีดังนั้นคุณจะได้รับการอภัย! ;)

@guest hi และยินดีต้อนรับสู่เว็บไซต์! ฉันแปลงคำตอบของคุณเป็นความคิดเห็นเนื่องจากคำตอบควรโพสต์เมื่อพวกเขาตอบคำถามจริงเท่านั้น นี่ไม่ใช่ฟอรั่มในความรู้สึกแบบคลาสสิกและเราต้องการเพียงคำถามและคำตอบที่แท้จริงที่นี่ คุณอาจต้องการดูที่ศูนย์ช่วยเหลือหรือเยี่ยมชมเว็บไซต์เพื่อทำความเข้าใจกับเว็บไซต์ให้ดียิ่งขึ้น ที่กล่าวว่าพื้นหลังของฉันเป็นจริงในทางชีววิทยาดังนั้นใช่รหัสของฉันอยู่ไกลจากการทำความสะอาด :) อย่างไรก็ตามฉันไม่เห็นว่าวงเล็บจะช่วยได้ที่นี่ราคาคำพูดปกป้องตัวแปรแล้ว อะไรจะทำลายสิ่งนี้ที่วงเล็บจะป้องกัน?
terdon

@guest ah, ขออภัยลืมคุณไม่สามารถแสดงความคิดเห็น รู้สึกอิสระที่จะมาและอธิบายในการแชทฉันแน่ใจว่าฉันอาจเรียนรู้บางสิ่งบางอย่าง
terdon

5

Oldschool เพียงแปลประโยคของคุณเป็นคำสั่งมาตรฐาน:

for file in *; do
    if head -n 1 "${file}" | grep -q 'PATTERN'; then
        cat "${file}"
    fi
done

สำหรับการเรียนรู้การทุบตีที่เป็นการเริ่มต้นที่ดี หากคุณต้องการวิธีแก้ปัญหาอย่างรวดเร็วให้ลองใช้คำตอบ awk หรือ perl-answer ทั้งดี แต่เป็นภาษาของตัวเองที่คุณต้องการ (และอาจต้องการ) เพื่อเรียนรู้

มันเป็นตัวอย่างที่ค่อนข้างง่ายดังนั้นหากคุณต้องการเรียนรู้เพิ่มเติมคุณสามารถลองแบบเดียวกันใน ruby, php, js (เช่นใน nodejs) หรือภาษาอื่น ๆ ที่อนุญาตการเข้าถึงไฟล์ แม้แต่ C / C ++ หรือ Java ก็ควรจัดการได้ง่ายด้วยภารกิจเล็ก ๆ


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