การแทนที่อักขระบางตัวในสตริงด้วยอักขระอื่น


279

ฉันมีสตริงเหมือนAxxBCyyyDEFzzLMNและฉันต้องการจะแทนที่เกิดขึ้นทั้งหมดของX , YและZกับ_

ฉันจะบรรลุสิ่งนี้ได้อย่างไร

ฉันรู้ว่าecho "$string" | tr 'x' '_' | tr 'y' '_'มันใช้งานได้ แต่ฉันต้องการที่จะทำในครั้งเดียวโดยไม่ต้องใช้ท่อ


คุณต้องการแทนที่ลำดับใด ๆ ของ x ติดต่อกัน, y's หรือ z ด้วยเครื่องหมายขีดล่างเดียวหรือคุณต้องการแทนที่แต่ละ x, y หรือ z ด้วยเครื่องหมายขีดล่างหนึ่งอัน? นอกจากนี้สิ่งที่เกี่ยวกับการผสมผสานลำดับเช่นAxyzB? สามขีดหรือหนึ่ง?
David Z

tr '[xyz]'จะแทนที่[และ]ด้วย อาร์กิวเมนต์ควรเป็นเพียงรายการของตัวละคร (แม้ว่าช่วงเช่นa-zจะไม่เป็นไรและในการใช้งานบางอย่างคลาสอักขระ POSIX เช่น[:digit:])
tripleee

คำตอบ:


329
echo "$string" | tr xyz _

จะเข้ามาแทนที่การเกิดขึ้นของแต่ละx, yหรือzที่มี_ให้A__BC___DEF__LMNในตัวอย่างของคุณ

echo "$string" | sed -r 's/[xyz]+/_/g'

จะเข้ามาแทนที่การเกิดซ้ำของx, yหรือzมีเพียงหนึ่งเดียว_ให้A_BC_DEF_LMNในตัวอย่างของคุณ


19
สำหรับ Mac ฉันได้รับสิ่งต่อไปนี้: sed: ตัวเลือกที่ผิดกฎหมาย - การใช้ r: sed script [-Ealn] [-i extension] [ไฟล์ ... ] sed [-Ealn] [-Ealn] [-i extension] [-e script] .. [-f script_file] ... ... [file ... ]
catanore

ฉันมีสตริงที่มี,[]{}()~ตัวอักษร ฉันต้องการแทนที่มันด้วยตัวละครพิเศษแต่ละตัวที่หลบหนีด้วย'\'ฉันจะทำสิ่งนี้ให้สำเร็จด้วยการยิงครั้งเดียวได้อย่างไร
inckka

2
@halakala Mac มาพร้อมรุ่น sed แตกต่างกันเล็กน้อย ดูคำถามนี้: unix.stackexchange.com/questions/13711/ … แทนคุณสามารถติดตั้ง "gnu-sed" ด้วยตัวจัดการแพ็กเกจ Homebrew จากนั้นใช้gsedไบนารี่: $ brew install gnu-sedจากนั้น$ gsed -r 's/[xyz]+/_/g'
John Kary

6
บน * BSD (และดังนั้น, OSX), sed -E(โดยทั่วไป) เทียบเท่ากับsed -rใน distros Linux หลายตัวหากคุณใช้sed 's/[xyz][xyz]*/_/g'คุณไม่จำเป็นต้องใช้ตัวเลือก แน่นอนนี่เทียบเท่ากับtr -s xyz _ความต้องการที่แท้จริงของsedที่นี่
tripleee

@inckka คุณไม่สามารถใช้trสิ่งนั้นได้ sed 's/[][{}()~,]/\\&/g'แต่จริงๆถามคำถามใหม่ถ้าคุณมีคำถามติดตาม (อย่าลังเลที่จะเชื่อมโยงกลับไปที่นี่สำหรับการอ้างอิงแน่นอน) บังเอิญ,และ~ไม่ใช่เมตาบอเรกต์ของ regex (แม้ว่าBash ~จะขยายไปถึง$HOMEบางตำแหน่งโดย Bash และ shell อื่น ๆshแต่ไม่ใช่)
tripleee

286

ใช้การขยายพารามิเตอร์ Bash :

orig="AxxBCyyyDEFzzLMN"
mod=${orig//[xyz]/_}

7
การเปลี่ยนตัวไม่ดี
Alexey

1
@ Alexey ตัวอย่างของฉันทำงานได้สำหรับฉัน (ทุบตี 4.3.11 (1) - ปล่อย) bashให้แน่ใจว่าคุณกำลังใช้ กระสุนอื่น ๆ อาจไม่ทำงาน (แม้ว่าบางคนจะ)
Matthew Flaschen

ขอบคุณ @MatthewFlaschen นี่คือสิ่งที่ฉันต้องทำเพื่อแทนที่ sed สำหรับพา ธ สัมบูรณ์ในสคริปต์ทุบตี (แทนที่ / ด้วย \ / ดังนั้น sed ยอมรับมัน)
Ryan G

1
@RyanG ทำไมต้องใช้sedถ้า bash มีการเปลี่ยนตัวในตัว?
MestreLion

@ MestreLion ที่อาจผิดพลาด แต่ฉันต้องการแทนที่ชื่อตัวแปรมาตรฐานในไฟล์จำนวนมากด้วยพา ธ สัมบูรณ์ที่ฉันใช้แทนที่ inplace แทน แต่คุณไม่สามารถมี "/" โดยไม่ต้องหลบหนีในคำสั่ง ฉันคบการดำเนินการร่วมกันในทุบตี นี่จะไม่ใช่วิธีที่ดีที่สุดในการจัดการสตริงด้วยการทุบตีหรือไม่?
Ryan G

111

คุณอาจพบว่าลิงค์นี้มีประโยชน์:

http://tldp.org/LDP/abs/html/string-manipulation.html

โดยทั่วไปแล้ว

ในการแทนที่การจับคู่แรกของ $ substring ด้วยการแทนที่ $:

${string/substring/replacement}

ในการแทนที่การจับคู่ทั้งหมดของ $ substring ด้วยการแทนที่ $:

${string//substring/replacement}

แก้ไข: โปรดทราบว่าสิ่งนี้ใช้กับตัวแปรที่ชื่อว่า $ string


16
โปรดทราบว่าสิ่งนี้ใช้งานได้กับตัวแปรชื่อ "string" ที่ไม่ได้อยู่ในสตริงตัวอักษร
mattdm

1
ที่เป็นประโยชน์มากที่สุดเนื่องจากมีการอ้างอิง
Os3

ทางออกที่ดีที่สุดและสั้นที่สุด
northtree

8
read filename ;
sed -i 's/letter/newletter/g' "$filename" #letter

^ ใช้สิ่งเหล่านี้มากเท่าที่คุณต้องการและคุณสามารถสร้างการเข้ารหัสพื้นฐานของคุณเอง


5

นี่คือโซลูชันที่มีการขยายพารามิเตอร์เชลล์ที่แทนที่เหตุการณ์ที่เกิดขึ้นหลาย ๆ อันด้วยสิ่งเดียว_:

$ var=AxxBCyyyDEFzzLMN
$ echo "${var//+([xyz])/_}"
A_BC_DEF_LMN

ขอให้สังเกตว่ารูปแบบต้องมีการจับคู่รูปแบบขยายเปิดด้วย+(pattern)

shopt -s extglob

อีกทางเลือกหนึ่งด้วย-sตัวเลือก ("บีบ") tr:

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