ปัญหาก็คือว่า เกรป
จะทำงานในแต่ละบรรทัด ไม่ใช่ทั้งไฟล์ ตราบเท่าที่ไฟล์มีขนาดเล็กพอที่จะใส่หน่วยความจำได้ (ซึ่งควรเป็นกรณีส่วนใหญ่ในปัจจุบัน) คุณสามารถใช้ grep's -z
ตั้งค่าสถานะเพื่อ slurp ทั้งไฟล์:
-z, --null-ข้อมูล
ปฏิบัติต่อข้อมูลอินพุตและเอาต์พุตเป็นลำดับของ
แต่ละบรรทัดสิ้นสุดด้วยศูนย์ไบต์ (ASCII NUL
character) แทนการขึ้นบรรทัดใหม่ เช่นเดียวกับตัวเลือก -Z หรือ --null ตัวเลือกนี้สามารถใช้กับคำสั่งได้
เช่น sort -z เพื่อประมวลผลชื่อไฟล์ตามอำเภอใจ
ประเด็นต่อมาคือถ้าคุณผ่าน เกรป
บางอย่างที่มีการขึ้นบรรทัดใหม่ มันจะถือว่าเป็นรายการของรูปแบบที่จะ grep สำหรับ:
$string="1
> 2"
$ seq 10 | เกรป "$string"
1
2
10
"
ซึ่งหมายความว่าฉันเกรงว่าคุณจะต้องแสดงรูปแบบเป็นนิพจน์ทั่วไปที่เหมาะสม:
\n\nทดสอบ1\n\nทดสอบ2\n\n
อย่างไรก็ตาม นี่ก็หมายความว่าคุณต้องการ -ป
ตั้งค่าสถานะเพื่อเปิดใช้งานนิพจน์ทั่วไปที่เข้ากันได้กับ Perl ดังนั้น \n
จะทำงาน.
ฉันสร้างไฟล์ทั้งสองนี้เพื่อสาธิต:
$ ไฟล์แมว1
นี่คือการทดสอบ:
ทดสอบ1
ทดสอบ2
และอีกอันหนึ่ง
ไฟล์แมว $2
นี่คือการทดสอบ:
ทดสอบ1
ทดสอบ2
และอีกอันหนึ่ง
เมื่อใช้ไฟล์ทั้งสองนี้และข้อมูลด้านบน คุณสามารถทำได้:
$ grep -Pz '\n\ntest1\n\ntest2\n\n' file1
$
$ grep -Pz '\n\ntest1\n\ntest2\n\n' ไฟล์2
นี่คือการทดสอบ:
ทดสอบ1
ทดสอบ2
และอีกอันหนึ่ง
การรวมทั้งหมดนี้เข้าด้วยกันทำให้เรา:
string='\n\ntest1\n\ntest2\n\n'
ถ้า ! grep -Pzq "$string" test.txt; แล้ว
พิมพ์f "$string" >> test.txt
ไฟ
หรือตามที่แนะนำโดย @steeldriver ในความคิดเห็น คุณสามารถใช้ตัวแปรและแปลงการขึ้นบรรทัดใหม่เป็น \n
ในขณะที่บิน:
$ สตริง = "
ทดสอบ1
ทดสอบ2
"
$ ถ้า ! grep -Pzq "${string//$'\n'/\n}" test.txt; แล้ว
พิมพ์f "$string" >> test.txt
ไฟ
หากสตริงของคุณมีอักขระพิเศษที่มีความหมายในนิพจน์ทั่วไป ดังที่คุณแสดงในคำถามที่อัปเดตแล้ว แสดงว่าเป็นสถานการณ์ที่แตกต่างไปจากเดิมอย่างสิ้นเชิง สำหรับตัวอย่างที่คุณแสดง คุณต้องการบางสิ่งที่ซับซ้อนกว่านี้มาก แบบนี้:
searchString='\n\nif \[ -f ~/.script \]; จากนั้น\s*\n\s*\.\s+~/\.script\s*\nfi\n\n'
พิมพ์สตริง='
ถ้า [ -f ~/.script ]; แล้ว
. ~/.script
ไฟ
'
ถ้า ! grep -Pzq "$searchString" test.txt; แล้ว
printf "%s" "$printString" >> test.txt
ไฟ