ค้นหาสตริงและพิมพ์ทุกอย่างก่อนและหลังภายในช่วง


9

ฉันมีไฟล์นี้:

sometext1{
string1
}

sometext2{
string2
string3
}

sometext3{
string4
string5
string6
}

ฉันต้องการที่จะค้นหาแฟ้มนี้เพื่อหาสตริงที่เฉพาะเจาะจงและพิมพ์ทุกอย่างก่อนที่สายนี้ขึ้นอยู่กับการเปิดและทุกอย่างหลังจากที่สายนี้ถึงปิด{ }ฉันพยายามที่จะบรรลุสิ่งนี้ด้วย sed แต่ถ้าฉันพยายามพิมพ์ทุกอย่างในช่วง/{/,/string2/ตัวอย่างเช่น sed พิมพ์สิ่งนี้:

sometext1{
string1
}

sometext2{
string2
sometext3{
string4
string5
string6
}

ถ้าฉันค้นหาสตริง "string2" ฉันต้องการผลลัพธ์เป็น:

sometext2{
string2
string3
}

ขอบคุณ


ตอนนี้ฉันพบว่าฉันต้องการหมายเลขบรรทัดของ ouput ในไฟล์ต้นฉบับเพื่อลบออกในภายหลัง ฉันลองเปลี่ยนคำสั่งที่ @ mikeserv จัดให้โดยไม่มีโชคฉันสับสนเล็กน้อยกับฟังก์ชั่นระงับการทำงานของ sed
rodrigo

ดี geez, rodrigo คุณไม่ได้บอกใครเลยนอกจากตัวคุณเอง ก็สามารถทำได้ grep -n '' <infile | sed ...แต่มันจะทำดีที่สุดเช่น sedคำสั่งจะต้องแก้ไข; บิต/แอดเดรสโดยเฉพาะ/ที่มองหา^จุดยึดด้านบนของบรรทัด grep -n '' | sed 'H;/{$/h;/^[^:]*:}/x;/{\n.*PATTERN/!d'ดังนั้นถ้าคุณกำลังใช้คำตอบของฉันคุณอาจจะทำ: บรรทัดเอาต์พุตทั้งหมดจะนำหน้าด้วยหมายเลขบรรทัดของไฟล์ดั้งเดิมตามด้วยโคลอนที่ชอบ1:sometext1{\n2:string1เป็นต้น sedจะกรองเฉพาะสิ่งที่จะกรองก่อนยกเว้นว่าแต่ละบรรทัดเอาต์พุตจะเปิดขึ้นพร้อมกับตัวเลข
mikeserv

คำตอบ:


9

นี่คือสองคำสั่ง หากคุณต้องการคำสั่งที่จดจ้องถึง.*{$บรรทัดสุดท้ายในลำดับ(เช่น @don_crissti ทำด้วยed)คุณสามารถทำได้:

sed 'H;/{$/h;/^}/x;/{\n.*PATTERN/!d'

... ซึ่งทำงานโดยการต่อท้ายทุกบรรทัดในHพื้นที่เก่าตาม\nอักขระ ewline เขียนทับhพื้นที่เก่าสำหรับทุกบรรทัดที่ตรงกัน{$และการสลับhช่องว่างเก่าและรูปแบบสำหรับทุกบรรทัดที่ตรง^}- และจึงเป็นการลบบัฟเฟอร์

มันพิมพ์เฉพาะเส้นที่ตรงกับ a {แล้ว\newline และPATTERNในบางจุด - และจะเกิดขึ้นทันทีหลังจากการแลกเปลี่ยนบัฟเฟอร์

มันจะลบบรรทัดใด ๆ ในชุดของการ{$แข่งขันไปยังลำดับสุดท้าย แต่คุณสามารถได้รับสิ่งที่รวมทั้งหมดเช่น:

sed '/PATTERN.*\n/p;//g;/{$/,/^}/H;//x;D'

สิ่งที่มันคือรูปแบบการสลับและhช่องว่างเก่าสำหรับทุก...{$.*^}.*ลำดับผนวกทุกบรรทัดภายในลำดับไปยังHพื้นที่เก่าต่อไปนี้\nตัวละครDewline และลบได้ถึง\nตัวละคร ewline แรกที่เกิดขึ้นในพื้นที่รูปแบบสำหรับทุกรอบวงจรก่อนที่จะเริ่มอีกครั้ง

แน่นอนว่าครั้งเดียวที่มันได้รับ\newline ในพื้นที่รูปแบบคือเมื่ออินพุตบรรทัดตรงกับ^}- จุดสิ้นสุดของช่วงของคุณ - และเมื่อมันรันสคริปต์อีกครั้งในโอกาสอื่น ๆ มันเพิ่งดึงอินพุทถัดไปตามปกติ

เมื่อPATTERNพบในพื้นที่รูปแบบเช่นเดียวกับ\newline แม้ว่าจะพิมพ์จำนวนมากก่อนที่จะเขียนทับด้วย^}อีกครั้ง(ดังนั้นจึงสามารถจบช่วงและล้างบัฟเฟอร์)

รับไฟล์อินพุตนี้(ขอบคุณดอน) :

sometext1{
string1
}

sometext2{
PATTERN
string3
}

sometext3{
string4
string5
string6
}

Header{
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}
}

พิมพ์ครั้งแรก:

sometext2{
PATTERN
string3
}
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}

... และที่สอง ...

sometext2{
PATTERN
string3
}
Header{
sometext4{
some string

string unknown

here's PATTERN and PATTERN again
and PATTERN too
another string here
}

@don_crissti - ฉันไม่รู้ มันเพียง delimits }ลำดับสำหรับการเริ่มต้นสอดคล้องกับ สิ่งนี้อาจเป็นประโยชน์สำหรับคนที่ชอบ ... open{\nsub;\n{ command; }\n}; close- แต่ฉันไม่แน่ใจว่าเป็นสิ่งที่เกิดขึ้นที่นี่ ...
mikeserv

สวัสดี @mikeserv - ฉันมีคำถามที่คล้ายกันที่ยกมาที่นี่unix.stackexchange.com/questions/232509/วิธีการแก้ปัญหาของคุณทำงานในไฟล์ขนาดเล็ก แต่ฉันมีไฟล์ขนาดใหญ่และฉันได้รับ "ค้างไว้ล้นพื้นที่" ข้อความผิดพลาด. คุณรู้ว่ามีโอกาสใดฉันจะแก้ไขปัญหานี้ได้อย่างไร ขอบคุณมาก
Narayan Akhade

@NarayanAkhade - ไม่ ไม่ได้โดยไม่ต้องยกเครื่องต่อไป นอกเสียจาก ... จะมีช่องสัญญาณขนาดใหญ่ที่ไม่มีใน{...}บล็อกหรือไม่ หากเป็นกรณีและคุณกำลังใช้วิธีการแก้ปัญหาครั้งแรกแล้วคุณอาจจะทำในช่วงเริ่มต้นแทนเพียง/{$/,/^}/H Hแต่ถ้าคุณลองวิธีที่สองและยังพบข้อผิดพลาดเดียวกันก็ไม่น่าจะช่วยได้เพราะวิธีนั้นทำอยู่แล้ว และไม่ลดราคาedเช่นกัน อย่าได้คำตอบที่ดีมากที่นี่และedสามารถนำไปใช้กับไฟล์บัฟเฟอร์ชั่วคราวได้อย่างง่ายดายเช่นกันซึ่งควรป้องกันการบัฟเฟอร์ของบัฟเฟอร์มากเกินไป
mikeserv

6

นี่คือทางออกของed:

ed -s filename <<< $'g/PATTERN/?{?,/}/p\nq\n'

นั่นคือ:

g/PATTERN/     # mark each line matching PATTERN  
?{?,/}/p       # for each marked line, print all lines from the previous { up to the next }  
q              # quit editor

สมมติว่ามีเพียงบรรทัดเดียวPATTERNระหว่างแต่ละคู่{ }มิฉะนั้นคุณจะได้รับผลลัพธ์ที่ซ้ำกันสำหรับแต่ละบรรทัดเพิ่มเติมด้วยPATTERNภายในบล็อกเดียวกัน
มันจะทำงานสำหรับหลาย ๆ คน{ }ที่มีการจับคู่บรรทัดเดียวPATTERNเช่นสำหรับไฟล์ทดสอบด้วยPATTERNในสองส่วนที่แตกต่างกัน:

sometext1{
string1
}

sometext2{
PATTERN
string3
}

sometext3{
string4
string5
string6
}

Header{
sometext4{
some string

string unknown

here's PATTERN again

another string here
}
}

วิ่ง

ed -s sample <<< $'g/PATTERN/?{?,/}/p\nq\n'

เอาท์พุท:

sometext2{
PATTERN
string3
}
sometext4{
some string

string unknown

here's PATTERN again

another string here
}

ฉันเอามากจากนี้จริง ๆ แล้ว! ขอบคุณมาก ๆ!
mikeserv

ฉันไม่ทราบด้วยซ้ำถึงคำสั่งนี้ ขอบคุณ
rodrigo

4

ด้วยpcregrep:

pcregrep -M '(?s)\{[^}]*PATTERN.*?\}'

หรือด้วย GNU grepหากอินพุตไม่ได้มี NUL ไบต์:

grep -Poz '.*(?s)\{[^}]*PATTERN.*?\}'

0
$ awk 'BEGIN{RS="\n\n"; FS="[{}]"} {if ($2 ~ /string4/) {print $2}}' t1.txt
string4
string5
string6

ที่อยู่:

  • string4 -> สตริงที่จะจับคู่
  • t1.txt -> มีเนื้อหาไฟล์ที่กล่าวถึงในแบบสอบถาม

-2

ชื่อไฟล์ sed -n '/ string / p'

-n เมื่อมีการเพิ่มการทำงานที่ถูกระงับของ sed คำสั่งนี้อาจไม่ได้ให้สิ่งที่คุณต้องการ แต่มันควรจะแทนที่สตริง

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