sed สามารถแทนที่อักขระบรรทัดใหม่ได้หรือไม่


42

มีปัญหากับตัวละครใหม่และตัวละครใหม่หรือไม่?
ฉันมีไฟล์ test.txt พร้อมเนื้อหาดังต่อไปนี้

aaaaa  
bbbbb  
ccccc  
ddddd  

ต่อไปนี้ใช้ไม่ได้:
sed -r -i 's/\n/,/g' test.txt

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

หากนี่คือผลข้างเคียงของการประมวลผลไฟล์ทีละบรรทัดฉันจะสนใจว่าทำไมสิ่งนี้จึงเกิดขึ้น ฉันคิดว่าgrepจะลบบรรทัดใหม่ sed ทำเช่นเดียวกันหรือไม่


1
ในกรณีนี้ sed อาจไม่ใช่เครื่องมือที่ดีที่สุดในการใช้ (เช่น "tr") มีเครื่องมือที่ใช้งานง่ายอ่านและดูแลรักษาง่ายขึ้นทำงานได้ดีขึ้น (โดยเฉพาะกับข้อมูลขนาดใหญ่) ฯลฯ ... อย่าใช้ค้อนของคุณเพื่อใส่สกรูเข้าไป (แม้ว่าจะใช้งานได้) คุณสามารถค้นหาการเปรียบเทียบได้ที่: http://slash4.de/blog/python/sed-replace-newline-or-python-awk-tr-perl-xargs.html
omoser

2
trจะเพิ่มส่วนท้าย,และจะส่งออกบรรทัดที่ไม่ได้ระบุ ดีที่สุดคือใช้pasteแทน:paste -sd , test.txt
Stéphane Chazelas

คำตอบ:


48

ด้วย GNU sedและที่ระบุPOSIXLY_CORRECTไม่ได้อยู่ในสภาพแวดล้อม (สำหรับอินพุตบรรทัดเดียว):

sed -i ':a;N;$!ba;s/\n/,/g' test.txt

จากhttps://stackoverflow.com/questions/1251999/sed-how-can-i-replace-a-newline-n :

  1. สร้างป้ายกำกับผ่านทาง :a
  2. ต่อท้ายบรรทัดปัจจุบันและบรรทัดถัดไปไปยังพื้นที่รูปแบบผ่าน N
  3. หากเราอยู่ก่อนบรรทัดสุดท้ายให้แยกสาขาไปยังป้ายกำกับที่สร้างขึ้น$!ba( $!หมายความว่าไม่ควรทำในบรรทัดสุดท้าย (เนื่องจากควรมีหนึ่งบรรทัดใหม่สุดท้าย))
  4. ในที่สุดการทดแทนจะแทนที่ทุกบรรทัดใหม่ด้วยเครื่องหมายจุลภาคบนพื้นที่รูปแบบ (ซึ่งเป็นไฟล์ทั้งหมด)

ดูเหมือนว่านี่จะบ่งบอกว่าปัญหาคือ sed อ่านทีละบรรทัด แต่ฉันไม่เข้าใจว่าทำไมถึงเป็นปัญหามันสามารถอ่านบรรทัดและแทนที่อักขระบรรทัดใหม่ (หรืออักขระสุดท้าย) ด้วย a
Jim

1
@ jim ดูเหมือนจะไม่ได้อยู่ในบัฟเฟอร์ที่จะจับคู่ แต่ฉันไม่คล่องแคล่วกับ sed บางทีคนอื่นสามารถหลั่งไฟบนที่ ฉันคิดว่าคุณควรขยายคำถามของคุณด้วยข้อมูลเฉพาะเพื่อให้ผู้คนมีแนวโน้มที่จะอ่านและหวังว่าจะได้คำตอบ
Anthon

ผลลัพธ์นี้ในba: Event not found
krb686

@ krb686 "นี่คืออะไร" ที่คุณอ้างถึงคืออะไร? คุณรันsedคำสั่งด้านบนพร้อมตัวเลือกที่แน่นอนเหล่านั้นหรือ เกี่ยวกับสิ่งที่test.txt ไฟล์? เวอร์ชันใดของsed(ลองsed --version)
Anthon

@ แอนทันขออภัยฉันคิดว่าฉันตั้งใจจะพูดว่า ผมอ่านโพสต์ SO อื่นที่แจ้งผมว่า csh !ต้องการให้ฉันที่จะหลบหนี ที่น่าสนใจที่ยังคงไม่ได้ทำงานสำหรับฉันและฉันสิ้นสุดต้องเป็นสองเท่าหลบหนี!ในของฉัน.cshสคริปต์ ตอนนี้ฉันไม่มีปัญหาจริงๆ แต่คุณรู้หรือไม่ว่าทำไมถึงเป็นเช่นนั้น สิ่งที่ทำงานให้ฉันคือsed :a;N;$\\!ba;s/\n/ /g'
krb686

16

สิ่งนี้ใช้ได้กับ GNU sed:

sed -z 's/\n/,/g' 

-z รวมอยู่ใน 4.2.2

NB -zเปลี่ยนตัวคั่นเป็นอักขระ null ( \0) หากอินพุตของคุณไม่มีอักขระ null ใด ๆ อินพุตทั้งหมดจะถือเป็นบรรทัดเดียว นี้สามารถมาด้วยข้อ จำกัด

เพื่อหลีกเลี่ยงการขึ้นบรรทัดใหม่ของบรรทัดสุดท้ายคุณสามารถเปลี่ยนกลับได้:

sed -z 's/\n/,/g;s/,$/\n/'

(ซึ่งเป็นsedไวยากรณ์ของGNU อีกครั้ง แต่มันไม่สำคัญเนื่องจากสิ่งทั้งหมดเป็น GNU เท่านั้น)


3
สิ่งนี้จะแทนที่บรรทัดใหม่ที่ต่อท้ายซึ่งอาจไม่ใช่สิ่งที่ OP ต้องการ ... เปรียบเทียบผลลัพธ์กับโซลูชันของmikeserv
don_crissti

7

จากเว็บไซต์ของ Oracle:

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

โดยทั่วไปหมายความว่าเนื่องจาก sed คือการอ่านทีละบรรทัดอักขระบรรทัดใหม่จะไม่ตรงกัน

ทางออกจากhttps://stackoverflow.com/questions/1251999/sed-how-can-i-replace-a-newline-nคือ:

sed ':a;N;$!ba;s/\n/,/g'

หรือในรุ่นพกพา (โดยไม่ต้อง;ต่อรองหลังเครื่องหมายกำกับการข้าม)

sed -e ':a' -e 'N;$!ba' -e 's/\n/,/g'

คำอธิบายเกี่ยวกับวิธีการใช้งานในหน้านั้น


ฉันใช้รูปแบบที่ปรับเปลี่ยนแล้วเพื่อแยกบันทึก VPN และใส่ข้อมูลผู้ใช้ "รับรองความถูกต้อง" และประทับเวลาในบรรทัดเดียวกัน ไชโย!
user208145

โปรดทราบว่าไวยากรณ์นั้นเป็น GNU ที่เฉพาะเจาะจงและแม้กระทั่งกับ GNU sedหาก POSIXLY_CORRECT อยู่ในสภาพแวดล้อมและอินพุตมีเพียงหนึ่งบรรทัดจะไม่มีผลลัพธ์
Stéphane Chazelas

5

sedลบ\newline ต่อท้ายทุกครั้งก่อนที่จะเติมพื้นที่รูปแบบจากนั้นผนวกหนึ่งก่อนที่จะเขียนผลลัพธ์ของสคริปต์ \newline สามารถจะมีในรูปแบบพื้นที่โดยวิธีการต่าง ๆ - แต่ไม่เคยถ้ามันไม่ได้เป็นผลมาจากการแก้ไข นี่เป็นสิ่งสำคัญ - \newlines ในsedพื้นที่รูปแบบของการสะท้อนการเปลี่ยนแปลงเสมอและไม่เคยเกิดขึ้นในกระแสอินพุต \newlines เป็นตัวคั่นเดียวที่sedder สามารถนับได้ด้วยอินพุตที่ไม่รู้จัก

หากคุณต้องการแทนที่\newlines ทั้งหมดด้วยเครื่องหมายจุลภาคและไฟล์ของคุณไม่ใหญ่มากคุณสามารถทำได้:

sed 'H;1h;$!d;x;y/\n/,/'

ซึ่งจะผนวกทุกบรรทัดอินพุตเข้ากับhพื้นที่เก่า - ยกเว้นบรรทัดแรกซึ่งจะแทนที่ทับhช่องว่างเก่า - \nแทนอักขระ ewline จากนั้นจะdลบทุกบรรทัดไม่ใช่บรรทัด$!สุดท้ายจากเอาต์พุต ในHช่องว่างบรรทัดเก่าและรูปแบบบรรทัดสุดท้ายมีการxเปลี่ยนแปลงe และ\nอักขระ ewline ทั้งหมดจะถูกy///แปลเป็นเครื่องหมายจุลภาค

สำหรับไฟล์ขนาดใหญ่สิ่งต่าง ๆ ประเภทนี้ถูกผูกไว้เพื่อทำให้เกิดปัญหา - sedบัฟเฟอร์บนขอบของบรรทัด


2

อีกวิธีหนึ่งคุณสามารถใช้ไวยากรณ์ที่ง่ายขึ้นเล็กน้อย:

sed ':a;N;s/\n/,/g;ba'

... เพียงแค่เปลี่ยนลำดับ


3
แต่รันsคำสั่งสำหรับแต่ละบรรทัดอินพุตบนพื้นที่รูปแบบที่ใหญ่ขึ้นเรื่อย ๆ
Stéphane Chazelas

1

มีบางอย่างที่ดีมากเป็นsedมายากลที่นี่ และบางจุดที่ดีขึ้นเกี่ยวกับพื้นที่รูปแบบล้น ฉันชอบใช้sedแม้ว่าจะไม่ใช่วิธีที่ง่ายที่สุดเพราะมันกะทัดรัดและทรงพลัง อย่างไรก็ตามมันมีข้อ จำกัด และสำหรับข้อมูลจำนวนมากพื้นที่รูปแบบจะต้องเป็นแบบ Mahoosive

GNU พูดว่า:

สำหรับผู้ที่ต้องการเขียนสคริปต์แบบพกพาแบบพกพาโปรดทราบว่ามีการใช้งานบางอย่างเพื่อจำกัดความยาวบรรทัด (สำหรับรูปแบบและพื้นที่ว่าง) ไม่เกิน 4000 ไบต์ มาตรฐาน posix ระบุว่าการปรับใช้ sed จะต้องสนับสนุนความยาวบรรทัดอย่างน้อย 8192 ไบต์ Sed GNU นั้นไม่มีขีดจำกัดความยาวของสายในตัว ตราบใดที่มันสามารถ malloc () หน่วยความจำเพิ่มเติม (เสมือน) คุณสามารถป้อนหรือสร้างบรรทัดได้ตราบใดที่คุณต้องการ
อย่างไรก็ตามการเรียกซ้ำใช้เพื่อจัดการรูปแบบย่อยและการทำซ้ำไม่ จำกัด ซึ่งหมายความว่าพื้นที่สแต็กที่มีอยู่อาจ จำกัด ขนาดของบัฟเฟอร์ที่สามารถประมวลผลได้ในบางรูปแบบ

ฉันไม่ได้เพิ่มอะไรมาก แต่ฉันอยากจะชี้ให้คุณไปที่คำแนะนำเพื่อไปที่ใจเย็นๆ มันยอดเยี่ยมมาก http://www.grymoire.com/Unix/Sed.html

และนี่คือทางออกของฉัน:

for i in $(cat test.txt); do echo -n $i','; done; echo '' >> somewhere

มันใช้งานได้ดี



-1

\nสมมติว่าคุณต้องการที่จะเข้ามาแทนที่การขึ้นบรรทัดใหม่โดย ฉันต้องการทำเช่นนั้นดังนั้นนี่คือสิ่งที่ฉันทำ:

(echo foo; echo bar; echo baz) | sed -r '$!s/$/\\n/' | tr -d '\n' 
# Output: foo\nbar\nbaz

นี่คือสิ่งที่มันไม่เพราะทุกสายยกเว้นสุดท้าย , \nผนวก trจากนั้นการขึ้นบรรทัดใหม่ลบด้วย


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