จะแทรกขึ้นบรรทัดใหม่ด้านหน้ารูปแบบได้อย่างไร?


139

จะแทรกขึ้นบรรทัดใหม่ก่อนรูปแบบภายในบรรทัดได้อย่างไร?

ตัวอย่างเช่นสิ่งนี้จะแทรกขึ้นบรรทัดใหม่ด้านหลังรูปแบบนิพจน์ทั่วไป

sed 's/regex/&\n/g'

ทำเหมือนกัน แต่หน้าลายได้ยังไง?

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

some text (012)345-6789

ควรจะกลายเป็น

some text
(012)345-6789

เพียงแค่ทำซ้ำคำตอบฉันจะแทรกบรรทัดใหม่ / linebreak หลังบรรทัดโดยใช้ sedที่นี่ได้อย่างไร:sed '/regex/G'
Adam Schmideg

1
@NilsvonBarth ทำไมคำถามตรงไปตรงมาเป็นคำถามที่ไม่ดี?
Josh

คำตอบ:


181

ใช้งานได้ในbashและzshทดสอบบน Linux และ OS X:

sed 's/regexp/\'$'\n/g'

โดยทั่วไปแล้ว$ตามด้วยสตริงลิเทอรัลในเครื่องหมายคำพูดเดี่ยวจะbashทำการแทนที่แบ็กสแลชสไตล์ C เช่น$'\t'แปลเป็นแท็บลิเทอรัล พลัส sed ต้องการที่แท้จริงขึ้นบรรทัดใหม่ของคุณจะหนีไปกับเครื่องหมายเพราะฉะนั้นก่อน\ $และในที่สุดเครื่องหมายดอลลาร์เองก็ไม่ควรถูกยกมาเพื่อให้มันถูกตีความโดยเชลล์ดังนั้นเราจึงปิดใบเสนอราคาก่อน$และจากนั้นจึงเปิดอีกครั้ง

แก้ไข : ตามที่แนะนำในความคิดเห็นโดย @ mklement0 สิ่งนี้ใช้ได้เช่นกัน:

sed $'s/regexp/\\\n/g'

สิ่งที่เกิดขึ้นที่นี่คือ: ตอนนี้คำสั่ง sed ทั้งหมดเป็นสตริงสไตล์ C ซึ่งหมายถึงแบ็กสแลชที่ sed ต้องวางไว้ก่อนที่ลิเทอรัลบรรทัดใหม่ควรจะหนีด้วยแบ็กสแลชอื่น แม้ว่าจะอ่านได้มากขึ้น แต่ในกรณีนี้คุณจะไม่สามารถทำการแทนที่สตริงเชลล์ได้ (โดยไม่ทำให้น่าเกลียดอีก)


7
สิ่งนี้ทำให้ฉัน "บรรทัดใหม่ที่ไม่ใช้ Escape ภายในรูปแบบการแทนที่" บน OSX
Matt Gibson

@ Matt Gibson แปลกมากเพราะ "การขึ้นบรรทัดใหม่ที่ไม่ใช้ Escape" จะได้รับก็ต่อเมื่อคุณมีการขึ้นบรรทัดใหม่จริงโดยไม่มีเครื่องหมายแบ็กสแลชภายในรูปแบบการเปลี่ยนตัว รหัสด้านบนของฉันใช้งานได้จริงในเชลล์อื่น ๆ เช่น zsh, ksh
mojuba

3
@ Matt Gibson ... หรือถ้าคุณลืมแบ็กสแลชก่อน '$' \ n ในรหัสของฉัน
mojuba

7
ตามที่เขียนไว้นิพจน์เหล่านี้แทนที่นิพจน์ทั่วไปด้วยการขึ้นบรรทัดใหม่แทนที่จะแทรกขึ้นบรรทัดใหม่ตรงกลางบรรทัดที่มีอยู่ตามที่ร้องขอ sed '\(first match\)\(second match\)/\1\'$'\n''\2/g'นี่คือวิธีที่ผมใช้รูปแบบการแก้ไขของคำตอบนี้เพื่อแทรกบรรทัดใหม่ระหว่างสองรูปแบบการจับคู่: สังเกตเครื่องหมายคำพูดเดี่ยวสองคำหลัง \ n ส่วนแรกจะปิดส่วน " $" เพื่อไม่ให้ส่วนที่เหลือของบรรทัดได้รับผลกระทบ หากไม่มีเครื่องหมายคำพูดเหล่านั้น \ 2 จะถูกละเว้น
David Ravetti

12
อีกตัวเลือกหนึ่งคือการใช้เพียงครั้งเดียว สตริง ANSI C-ยกมา : sed $'s/regexp/\\\n/g'ซึ่งช่วยเพิ่มการอ่าน - ข้อแม้เพียงว่าแล้วคุณต้องเป็นสองเท่าของตัวอักษรทุก\ ตัวอักษร
mklement0

46

คำตอบอื่น ๆ บางคำใช้ไม่ได้กับ sed เวอร์ชันของฉัน การสลับตำแหน่ง&และ\nทำงาน

sed 's/regexp/\n&/g' 

แก้ไข: นี้ดูเหมือนจะไม่ทำงานบน OS X gnu-sedเว้นแต่คุณจะติดตั้ง


10
ฉันไม่แน่ใจว่ามันใช้ได้กับ sed ทุกเวอร์ชัน ฉันลองสิ่งนี้บน Mac ของฉันและ \ n ได้รับเอาต์พุตเป็น 'n'
Todd Gamblin

4
ใช้เวลา 15 นาทีบน Mac ในที่ทำงานของฉันก่อนที่จะอ่านคำตอบของคุณ ไป Apple!
Rick77

2
สำหรับผู้ที่ใช้ homebrew brew install gnu-sedตามด้วยgsed 's/regexp/\n&/g'
aaaaaa

2
... ตามด้วยecho 'alias sed=gsed' >> ~/.bashrc
Proximo

36

ใน sed คุณไม่สามารถเพิ่มบรรทัดใหม่ในสตรีมเอาต์พุตได้อย่างง่ายดาย คุณต้องใช้เส้นต่อเนื่องซึ่งไม่สะดวก แต่ใช้งานได้:

$ sed 's/regexp/\
&/'

ตัวอย่าง:

$ echo foo | sed 's/.*/\
&/'

foo

ดูรายละเอียดได้ที่นี่ หากคุณต้องการบางสิ่งที่น่าอึดอัดใจเล็กน้อยคุณสามารถลองใช้perl -peกับกลุ่มที่ตรงกันแทนการ sed:

$ echo foo | perl -pe 's/(.*)/\n$1/'

foo

$1 หมายถึงกลุ่มที่ตรงกันกลุ่มแรกในนิพจน์ทั่วไปโดยที่กลุ่มอยู่ในวงเล็บ


ทำไมคุณถึงบอกว่าคุณไม่สามารถเพิ่มบรรทัดใหม่ได้? คุณสามารถทำได้เพียงแค่ sed 's / regexp / & \ n / g' นั่นแหละ
Andres

2
นี่เป็นสิ่งที่ดูแฮ็กน้อยที่สุดที่คุณสามารถทำได้บน Mac เพื่อแทรกขึ้นบรรทัดใหม่ (\ n ใช้ไม่ได้กับเครื่อง Mac)
Pylinux

เวอร์ชัน perl สามารถแก้ไขได้เพื่อทำการแก้ไขperl -pi -e 's/(.*)/\n$1/' foo
Eponymous

2
@Andres: (ส่วนใหญ่) การใช้งาน Sed ที่มีคุณลักษณะเฉพาะ POSIX เช่นเวอร์ชัน BSD ที่มาพร้อมกับ OS X ไม่สนับสนุนลำดับการหลีกเลี่ยงอักขระควบคุมในส่วนการทดแทนของการsเรียกใช้ฟังก์ชัน (ไม่เหมือนกับการใช้งานGNU Sed ซึ่งไม่) . คำตอบข้างต้นใช้ได้กับการใช้งานทั้งสองแบบ สำหรับภาพรวมของความแตกต่างทั้งหมดให้ดูที่นี่
mklement0

29

ใน Mac ของฉันสิ่งต่อไปนี้จะแทรก 'n' ตัวเดียวแทนการขึ้นบรรทัดใหม่

sed 's/regexp/\n&/g'

สิ่งนี้แทนที่ด้วย newline:

sed "s/regexp/\\`echo -e '\n\r'`/g"

ฉันกำลังทำการแก้ไขแบบอินไลน์sed -i '' -e ...และมีปัญหากับคา^Mเร็ต M (ctrl + m) ในการเขียนไฟล์ ฉันลงเอยด้วยการใช้ perl กับ params เดียวกัน
Steve Tauber

2
โปรดทราบว่ารหัสที่สองแทรกรหัสบรรทัดใหม่พิเศษ LF CR (ย้อนกลับของ MS-DOS CR LF)! ทั้งระบบปฏิบัติการที่เหมือน Unix และ Mac OS X ใช้แค่ LF ( \n)
pabouk

อย่างอื่นในการแสดงออกที่ใจเย็นของฉันทำให้เกิดความไม่พอใจอย่างมาก (แม้ว่ามันจะทำงานได้ดีโดยไม่ต้องขึ้นecho...บรรทัดใหม่) ที่ฉันทำสิ่งนี้เป็นกลุ่ม
Ahmed Fasih

1
หรือเพียงแค่: sed "s/regexp/`echo`/g"- สิ่งนี้จะสร้าง LF เดียวแทนที่จะเป็น LF-CR
mojuba

2
@mojuba: ไม่: `echo`จะส่งผลให้สตริงว่างเนื่องจากการแทนที่คำสั่งจะตัดบรรทัดใหม่ที่ต่อท้ายทั้งหมดอย่างสม่ำเสมอ ไม่มีวิธีใดที่จะใช้การแทนที่คำสั่งเพื่อแทรกบรรทัดใหม่เดียวโดยตรง (และการแทรก\n\r- กล่าวคือ CR เพิ่มเติม - เป็นความคิดที่แย่มาก)
mklement0

15
echo one,two,three | sed 's/,/\
/g'

1
+1 ทำงานได้อย่างสมบูรณ์แบบและค่อนข้างตรงไปข้างหน้า / จำง่าย
gMale

2
คำตอบนี้เป็นจริงsedวิธีการแก้ปัญหามากกว่าการทุบตีการแก้ปัญหา สิ่งใดก็ตามที่ใช้โครงสร้างเช่น$'\n'อาศัยเชลล์เพื่อสร้างบรรทัดใหม่ โซลูชันดังกล่าวอาจไม่สามารถพกพาได้ อันนี้คือ. แน่นอนว่ามันซ้ำกับตัวอย่างที่สองในคำตอบของ tgamblin จากปี 2009 ด้วย
ghoti

10

ในกรณีนี้ฉันไม่ใช้ sed ฉันใช้ tr.

cat Somefile |tr ',' '\012' 

ซึ่งจะใช้เครื่องหมายจุลภาคและแทนที่ด้วยการกลับแคร่


1
ฉันพบว่าสิ่งนี้ใช้ได้เช่นกัน: cat Somefile | tr ',' '\n'YMMV
Mr. Lance E Sloan

10

คุณสามารถใช้ perl one-liners ได้เหมือนกับที่คุณทำกับ sed ด้วยข้อได้เปรียบของการสนับสนุนการแสดงออกปกติของperlเต็มรูปแบบ(ซึ่งมีประสิทธิภาพมากกว่าสิ่งที่คุณได้รับจาก sed) นอกจากนี้ยังมีการเปลี่ยนแปลงน้อยมากในแพลตฟอร์ม * nix - โดยทั่วไปแล้ว perl จะเป็น perl ดังนั้นคุณจึงไม่ต้องกังวลว่าจะทำให้ sed เวอร์ชันเฉพาะของระบบของคุณทำในสิ่งที่คุณต้องการได้อย่างไร

ในกรณีนี้คุณสามารถทำได้

perl -pe 's/(regex)/\n$1/'

-pe ทำให้ perl เป็นลูป "ดำเนินการและพิมพ์" เหมือนกับโหมดการทำงานปกติของ sed

' ใส่เครื่องหมายคำพูดทุกอย่างเพื่อให้เชลล์ไม่รบกวน

()โดยรอบ regex เป็นตัวดำเนินการจัดกลุ่ม $1ทางด้านขวาของการเปลี่ยนตัวจะพิมพ์สิ่งที่จับคู่ไว้ใน parens เหล่านี้

สุดท้าย\nเป็นนิวไลน์

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

\(\d\d\d\)\d\d\d-\d\d\d\d

\(หรือ\)จับคู่พาเรนตามตัวอักษรและ\dจับคู่ตัวเลข

ดีกว่า:

\(\d{3}\)\d{3}-\d{4}

ฉันนึกภาพออกว่าตัวเลขในเครื่องหมายวงเล็บทำหน้าที่อะไร

นอกจากนี้คุณสามารถใช้ตัวคั่นอื่นที่ไม่ใช่ / สำหรับ regex ของคุณ ดังนั้นหากคุณต้องการจับคู่ / คุณไม่จำเป็นต้องหลบหนี ข้อใดข้อหนึ่งด้านล่างเทียบเท่ากับนิพจน์ทั่วไปที่จุดเริ่มต้นของคำตอบของฉัน ในทางทฤษฎีคุณสามารถแทนที่ อักขระใด ๆสำหรับมาตรฐาน / 's

perl -pe 's#(regex)#\n$1#'
perl -pe 's{(regex)}{\n$1}'

ความคิดสุดท้ายสองสาม

ใช้-neแทนการ-peทำงานในลักษณะเดียวกัน แต่จะไม่พิมพ์ตอนท้ายโดยอัตโนมัติ อาจเป็นประโยชน์หากคุณต้องการพิมพ์ด้วยตัวคุณเอง เช่นนี่คือ grep-alike ( m/foobar/เป็นการจับคู่นิพจน์ทั่วไป):

perl -ne 'if (m/foobar/) {print}'

-lหากคุณกำลังมองหาการจัดการกับการขึ้นบรรทัดใหม่ลำบากและคุณต้องการที่จะได้รับการจัดการอย่างน่าอัศจรรย์สำหรับคุณเพิ่ม ไม่มีประโยชน์สำหรับ OP ที่ทำงานกับข่าวใหม่

เคล็ดลับโบนัส - หากคุณติดตั้งแพ็คเกจ pcre มาพร้อมกับpcregrepซึ่งใช้ regexes ที่เข้ากันได้กับ perl เต็มรูปแบบ


4

อืมเพิ่งหนีออกมาบรรทัดใหม่ดูเหมือนจะใช้งานได้ในเวอร์ชันล่าสุดsed(ฉันมี GNU sed 4.2.1)

dev:~/pg/services/places> echo 'foobar' | sed -r 's/(bar)/\n\1/;'
foo
bar

1
ดังที่ได้กล่าวไปแล้วสิ่งนี้ใช้ได้กับ GNU sed เวอร์ชันต่างๆ แต่ไม่ใช่ sed ที่มาพร้อมกับ macOS
Mr. Lance E Sloan

4
echo pattern | sed -E -e $'s/^(pattern)/\\\n\\1/'

ทำงานได้ดีกับ El Captitan ด้วย()การสนับสนุน


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

3

ในการแทรกบรรทัดใหม่เพื่อส่งออกสตรีมบน Linux ฉันใช้:

sed -i "s/def/abc\\\ndef/" file1

อยู่ที่ไหนfile1:

def

ก่อนที่จะเปลี่ยนในสถานที่ sed และ:

abc
def

หลังจากเปลี่ยนในสถานที่ sed. โปรดสังเกตการใช้\\\n. หากรูปแบบที่มีอยู่ภายในนั้นหลบหนีโดยใช้"\"


สำหรับฉันรหัสด้านบนใช้ไม่ได้ sedแทรก\nแทน LF เนื่องจากได้รับ\\nในพารามิเตอร์จากเชลล์ - รหัสนี้ใช้ได้: sed -i "s/def/abc\ndef/" file1. --- GNU sed version 4.2.1, GNU bash, version 4.1.2(1) / 4.2.25(1)(CentOS รุ่น 6.4 / Ubuntu 12.04.3)
pabouk

2

ใน sed คุณสามารถอ้างอิงกลุ่มในรูปแบบของคุณด้วย "\ 1", "\ 2", .... ดังนั้นหากรูปแบบที่คุณกำลังมองหาคือ "PATTERN" และคุณต้องการแทรก "ก่อน" ไว้ข้างหน้า คุณสามารถใช้แซนส์หนี

sed 's/(PATTERN)/BEFORE\1/g'

กล่าวคือ

  sed 's/\(PATTERN\)/BEFORE\1/g'

เพิ่งทำ: testfile contents = "ABC ABC ABC" เรียกใช้ไฟล์ทดสอบ "sed 's / \ (ABC \) / \ n \ 1 / g' ได้ขึ้นบรรทัดใหม่ทดลองใช้ Escape พยายามเพิ่มทีละ 1 รายการในรูปแบบของคุณเช่นตรวจสอบให้แน่ใจว่าคุณตรงกับ จากนั้นตรวจสอบการจับคู่กลุ่มจากนั้นเพิ่มการตรวจสอบขึ้นบรรทัดใหม่
Steve B.

ฉันลองแค่นั้นและได้รับ "nABC nABC nABC" คุณกำลังใช้ sed เวอร์ชันอื่นอยู่หรือไม่
Todd Gamblin

การหนีกระสุนอาจเข้ามาขัดขวางความพยายามของ tgamblin การใส่ข้อโต้แย้งที่สมบูรณ์ในเครื่องหมายคำพูดเดียวเช่น Steve B ควรแก้ไขปัญหานั้น เป็นไปได้ว่า sed เวอร์ชันต่างๆไม่เข้าใจ \ n สำหรับ newline
Dan Pritts

2

คุณสามารถทำได้ด้วย awk โดยใช้-vเพื่อระบุรูปแบบ:

awk -v patt="pattern" '$0 ~ patt {gsub(patt, "\n"patt)}1' file

ตรวจสอบว่าบรรทัดมีรูปแบบที่กำหนดหรือไม่ ถ้าใช่มันจะต่อท้ายบรรทัดใหม่ที่จุดเริ่มต้น

ดูตัวอย่างพื้นฐาน:

$ cat file
hello
this is some pattern and we are going ahead
bye!
$ awk -v patt="pattern" '$0 ~ patt {gsub(patt, "\n"patt)}1' file
hello
this is some 
pattern and we are going ahead
bye!

โปรดทราบว่าจะมีผลกับรูปแบบทั้งหมดในบรรทัด:

$ cat file
this pattern is some pattern and we are going ahead
$ awk -v patt="pattern" '$0 ~ patt {gsub(patt, "\n"patt)}1' d
this 
pattern is some 
pattern and we are going ahead

1
1 ทำอะไรในสิ่งนี้?
whatahitson

1
@whatahitson 1ใช้ใน Awk {print $0}เป็นไปจดชวเลข เหตุผลก็คือเงื่อนไขใด ๆ ที่ประเมินเป็น True ทริกเกอร์การดำเนินการเริ่มต้นของ Awk ซึ่งประกอบด้วยการพิมพ์บันทึกปัจจุบัน
fedorqui 'SO หยุดทำร้าย'

1

สิ่งนี้ใช้ได้กับ MAC สำหรับฉัน

sed -i.bak -e 's/regex/xregex/g' input.txt sed -i.bak -e 's/qregex/\'$'\nregex/g' input.txt

Dono ว่ามันสมบูรณ์แบบ ...


1

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

#!/bin/bash
# script: add_domain
# using fixed values instead of command line parameters $1, $2
# to show typical variable values in this example
ipaddr="127.0.0.1"
domain="example.com"
# no need to escape $ipaddr and $domain values if we use separate quotes.
sudo sed -i '$a \\n'"$ipaddr www.$domain $domain" /etc/hosts

สคริปต์จะต่อท้ายบรรทัดใหม่\nตามด้วยข้อความอีกบรรทัดต่อท้ายไฟล์โดยใช้sedคำสั่งเดียว


1
sed -e 's/regexp/\0\n/g'

\ 0คือโมฆะดังนั้นนิพจน์ของคุณจะถูกแทนที่ด้วย null (ไม่มีอะไร) จากนั้น ...
\ nคือบรรทัดใหม่

ในบางรสชาติของ Unix ไม่ได้ผล แต่ฉันคิดว่ามันเป็นวิธีแก้ปัญหาของคุณ

echo "Hello" | sed -e 's/Hello/\0\ntmow/g'
Hello
tmow

0

ใน vi บน Red Hat ฉันสามารถแทรกการส่งคืนแคร่โดยใช้เพียงอักขระ \ r ฉันเชื่อว่าสิ่งนี้ดำเนินการภายใน 'ex' แทนที่จะเป็น 'sed' แต่มันก็คล้ายกันและ vi อาจเป็นอีกวิธีในการแก้ไขจำนวนมากเช่นการแก้ไขโค้ด ตัวอย่างเช่น. ฉันล้อมรอบคำค้นหาที่มีคำสั่ง if ที่ยืนยันในการคืนค่าขนส่งหลังจากการจัดฟัน:

:.,$s/\(my_function(.*)\)/if(!skip_option){\r\t\1\r\t}/

โปรดทราบว่าฉันยังให้มันแทรกบางแท็บเพื่อให้สิ่งต่างๆสอดคล้องกันดีขึ้น


0

ในกรณีของฉันวิธีการด้านล่างใช้ได้ผล

sed -i 's/playstation/PS4/' input.txt

สามารถเขียนเป็น:

sed -i 's/playstation/PS4\nplaystation/' input.txt


เพลย์สเตชันPS4

พิจารณาใช้\\ nในขณะที่ใช้ในสตริงลิเทอรัล

  • sed : เป็นโปรแกรมแก้ไขสตรีม

  • -i : อนุญาตให้แก้ไขไฟล์ต้นฉบับ

  • + : เป็นตัวคั่น

ฉันหวังว่าข้อมูลข้างต้นจะเหมาะกับคุณ😃

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