วิธีการค้นหาและแทนที่สตริงโดยไม่ต้องใช้คำสั่ง Sed?


16

ในฐานะที่เราทุกคนรู้ว่าsedมีประสิทธิภาพอย่างมากในการค้นหาและแทนที่สตริงเช่นค้นหา 'a' และแทนที่มัน sed 's/a/b/g''B':

เป็นไปได้ไหมที่จะทำสิ่งนี้กับคำสั่งหรือเชลล์สคริปต์แทนsed?

นี่สำหรับระบบ linux ที่ถูกครอบตัดสำหรับทีวีที่ไม่มีsedคำสั่ง ดังนั้นฉันต้องใช้คำสั่งหรือสคริปต์อื่นแทนsed 's/a/b/g'. –


ที่จริงแล้วนั่นเป็นเพียงการแสดงออกตามปกติของการทดแทน เครื่องมือใด ๆ หรือภาษาที่มีความสามารถที่จะจัดการกับสิ่งดังกล่าวจะสามารถที่จะทำเช่นเดียวกัน $var=~s/a/b/gแต่มีไวยากรณ์ต่างๆ: gsub(/a/,"b",var), var.gsub(/a/,'b'), var.replace(/a/g,'b'), preg_replace("/a/","b",$var), regsub -all a b $var, นอกจากนั้นเครื่องมือและภาษาจำนวนมากยังสามารถทำการแทนที่สตริงข้อความธรรมดาได้ ดังนั้นคำถามของคุณค่อนข้างกว้าง
จัดการ

1
ทำไม? คุณพยายามแก้ไขปัญหาอะไร
Gilles 'หยุดชั่วร้าย'

ระบบ linux ที่ถูกครอบตัดสำหรับทีวีไม่มีคำสั่ง sed ดังนั้นฉันจึงต้องใช้คำสั่งหรือสคริปต์อื่นแทนการใช้ 's / a / b / g'
binghenzq

คำตอบ:


12

ใช่มีหลายวิธีในการทำเช่นนี้ คุณสามารถใช้awk, perlหรือbashจะทำกิจกรรมเหล่านี้เช่นกัน โดยทั่วไปแล้วsedอาจเป็นเครื่องมือที่มีประโยชน์มากที่สุดสำหรับการทำงานประเภทนี้

ตัวอย่าง

ว่าฉันมีข้อมูลตัวอย่างนี้ในไฟล์data.txt:

foo bar 12,300.50
foo bar 2,300.50
abc xyz 1,22,300.50

awk

$ awk '{gsub("foo", "foofoofoo", $0); print}' data.txt 
foofoofoo bar 12,300.50
foofoofoo bar 2,300.50
abc xyz 1,22,300.50

Perl

$ perl -pe "s/foo/foofoofoo/g" data.txt 
foofoofoo bar 12,300.50
foofoofoo bar 2,300.50
abc xyz 1,22,300.50

การแก้ไขแบบอินไลน์

ตัวอย่างข้างต้นสามารถแก้ไขไฟล์ได้โดยตรง ตัวอย่าง Perl เป็นเรื่องเล็กน้อย เพียงเพิ่ม-iสวิตช์

$ perl -pie "s/foo/foofoofoo/g" data.txt 

สำหรับawkโดยตรงน้อยกว่าเล็กน้อย แต่มีประสิทธิภาพเท่า:

$ { rm data.txt && awk '{gsub("foo", "foofoofoo", $0); print}' > data.txt; } < data.txt

วิธีนี้จะสร้าง sub-shell ที่มีเครื่องหมายปีกกา '{... } `ซึ่งมีการเปลี่ยนเส้นทางไฟล์ไปที่นี่:

$ { ... } < data.txt

เมื่อไฟล์ถูกเปลี่ยนเส้นทางไปที่ sub-shell แล้วไฟล์นั้นจะถูกลบและawkจะทำงานกับเนื้อหาของไฟล์ที่อ่านเข้าไปใน sub-shells STDIN เนื้อหานี้จะถูกประมวลผลโดยawkและเขียนออกไปเป็นชื่อไฟล์เดียวกับที่เราเพิ่งลบไปแทนที่มันได้อย่างมีประสิทธิภาพ


ขอบคุณสำหรับคำตอบของคุณและฉันจะลองมันในวันทำงานถัดไป แต่ฉันไม่แน่ใจว่ามันทำงานได้ดีเพราะคำสั่งบางอย่างอาจไม่มีอยู่ในระบบ Linux ที่ถูกครอบตัดของทีวีเช่น 'sed'.So' ฉันยังต้องการใช้คำสั่ง 'find' , 'grep' และอื่น ๆ เพื่อแก้ปัญหา
binghenzq

@binghenzq - ฉันได้เพิ่มตัวอย่างที่อินไลน์แก้ไขไฟล์
slm

-1 ฉันไม่ค่อยลงคะแนน แต่ในกรณีนี้ประเด็นของคำถามดูเหมือนจะเป็นวิธีที่ง่ายกว่าแทนที่จะซับซ้อนมากกว่า / เท่า ๆ กันและมีแนวโน้มที่ต้องพึ่งพา หากคำถามนั้นเกี่ยวกับทางเลือกสำหรับการติดตั้งเครื่อง * แบบเต็มโปรดลอง +1 ด้วยคำตอบที่ดี
Michael Durrant

@MichaelDurrant - ฉันเพิ่งเพิ่มการแก้ไขแบบอินไลน์ที่ซับซ้อนเหล่านี้ b / c OP ขอให้พวกเขา OP กำหนดความต้องการที่ไม่ใช้sedไม่ใช่ I. Sed เป็นเครื่องมือที่เหมาะสมสำหรับการทำสิ่งทดแทนเช่นนี้และเขาเห็นได้ชัดว่าขอให้เข้าใจบทบาทของเครื่องมือเหล่านี้ได้ดีขึ้น พวกเขาทำไม มีหลายครั้งที่ ppl ในความรู้เพียงแค่พูดว่า "อย่าทำ" โดยไม่อธิบายว่าทำไมฉันจึงเป็นเช่นนั้น แต่ขอขอบคุณอย่างน้อยก็ออกความเห็นว่าทำไมคุณ DV
slm

แน่นอนฉันคิดว่ามันเป็นคำตอบที่ยอดเยี่ยมในทุกประเด็น ใช่ฉันเกลียด -1 โดยไม่มีคำอธิบาย
Michael Durrant

13

ทางเลือกแบบคลาสสิกสำหรับการเปลี่ยนตัวอักษรเดี่ยวคือtrคำสั่งที่ควรมีอยู่ในระบบใด ๆ :

$ echo "foobar" | tr a b   
foobbr

trดีกว่าsedสำหรับเรื่องนี้จริง ๆ แล้วตั้งแต่ใช้sed(ให้คนเดียวperlหรือawk) สำหรับการเปลี่ยนตัวอักษรเดี่ยวเหมือนกับการใช้ค้อนเลื่อนเพื่อฆ่าแมลงวัน

grep ไม่ได้ออกแบบมาสำหรับสิ่งนี้ แต่ไม่ได้แก้ไขอินพุตของมัน แต่จะค้นหาผ่านเท่านั้น

หรือคุณสามารถใช้ความสามารถในการทดแทนของเชลล์บางตัว ที่นี่ใช้ksh, zshหรือbashไวยากรณ์:

$ foo="foobar"
$ echo "${foo//a/b}"
foobbr

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


มีตัวเลือกในการละเว้นกรณี${foo//a/b}หรือไม่
AlikElzin-kilaka

@ AlikElzin-kilaka ฉันไม่กลัว คุณจะต้องใช้สิ่งที่มีความซับซ้อนมากขึ้นเช่นตัวอย่างเช่น: หรือให้ระดับตัวอักษร:echo "$foo" | sed 's/a/b/i echo ${foo//[aA]/b}
terdon

4

คุณสามารถใช้ Vim ในโหมด Ex:

ex -s -c '%s/a/b/g|x' file
  1. % เลือกทุกบรรทัด

  2. s แทน

  3. g ทดแทนทั่วโลก

  4. x บันทึกและปิด


ขอบคุณมาก เพียงเพื่อเพิ่มแฟล็ก -c คือการเรียกใช้คำสั่งเมื่อการแก้ไขเริ่มต้นขึ้น (เนื่องจาก ex เป็นตัวแก้ไข) และแฟล็ก -s เป็นโหมดสคริปต์อย่างใดอย่างหนึ่งที่ปิดใช้งานข้อเสนอแนะหรือบางคนชอบพูดโหมด slient อ้างอิงสำหรับข้อมูลเพิ่มเติม: ex-vi.sourceforge.net/ex.html
Jimmy MG Lim

3

หากคุณทำงานกับไฟล์มากกว่าสตรีมคุณสามารถใช้โปรแกรมแก้ไขข้อความมาตรฐานed:

printf '%s\n' ',s/a/b/g' w q | ed file.txt

สิ่งนี้ควรมีอยู่ใน * ระวัง เครื่องหมายจุลภาคใน',s/a/b/g'บอกedให้ทำงานในทุกบรรทัด (คุณสามารถใช้%ซึ่งจะคุ้นเคยมากขึ้นถ้าคุณคุ้นเคยกับเสียงเรียกเข้า) และส่วนที่เหลือเป็นคำค้นหามาตรฐานและแทนที่ wบอกให้เขียน (บันทึก) ไฟล์qบอกให้ออก

โปรดทราบว่าซึ่งแตกต่างจาก-iตัวเลือกของ sed (และตัวเลือกที่คล้ายกันในเครื่องมืออื่น ๆ ) สิ่งนี้จริง ๆ แล้วแก้ไขไฟล์ในสถานที่แทนที่จะโกงด้วยไฟล์ชั่วคราว

ฉันไม่คิดว่ามันเป็นไปได้ที่จะทำงานกับลำธารนี้ แต่แล้วฉันก็ไม่รู้อะไรมากedและฉันจะไม่แปลกใจถ้ามันมีความสามารถนั้นจริง ๆ (ปรัชญายูนิกซ์คือสิ่งที่มันเป็น)


2

การใช้คำสั่งancestor (ซึ่ง-sหมายถึงเงียบ (เงียบ) และเครื่องหมายจุลภาคก่อนคำสั่งหมายถึงดำเนินการในทุกบรรทัด):

เพียงพิมพ์บนSTDOUT :

ed -s file <<!
,s/a/b/g
,p
q
!

แทนที่ในสถานที่:

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