ฉันมี "ฉันรัก Suzi และ Marry" และฉันต้องการเปลี่ยน "Suzi" เป็น "Sara"
#!/bin/bash
firstString="I love Suzi and Marry"
secondString="Sara"
# do something...
ผลลัพธ์จะต้องเป็นดังนี้:
firstString="I love Sara and Marry"
ฉันมี "ฉันรัก Suzi และ Marry" และฉันต้องการเปลี่ยน "Suzi" เป็น "Sara"
#!/bin/bash
firstString="I love Suzi and Marry"
secondString="Sara"
# do something...
ผลลัพธ์จะต้องเป็นดังนี้:
firstString="I love Sara and Marry"
คำตอบ:
ในการแทนที่การเกิดขึ้นครั้งแรกของรูปแบบด้วยสตริงที่กำหนดให้ใช้:${parameter/pattern/string}
#!/bin/bash
firstString="I love Suzi and Marry"
secondString="Sara"
echo "${firstString/Suzi/$secondString}"
# prints 'I love Sara and Marry'
หากต้องการแทนที่เหตุการณ์ทั้งหมดให้ใช้:${parameter//pattern/string}
message='The secret code is 12345'
echo "${message//[0-9]/X}"
# prints 'The secret code is XXXXX'
(นี่คือการบันทึกไว้ในคู่มือทุบตีอ้างอิง , §3.5.3 "ขยายเชลล์พารามิเตอร์" .)
โปรดทราบว่า POSIX ไม่ได้ระบุคุณสมบัตินี้ - เป็นส่วนขยาย Bash - ดังนั้นเชลล์ Unix ทั้งหมดจึงไม่สามารถใช้งานได้ สำหรับเอกสารที่เกี่ยวข้อง POSIX ดูเปิด Group ฐานมาตรฐานข้อมูลจำเพาะทางเทคนิค, ฉบับที่ 7ที่เชลล์และสาธารณูปโภคปริมาณ§2.6.2 "การขยายตัวพารามิเตอร์"
\n
ในบริบทนั้นจะเป็นตัวแทนของตัวเองไม่ใช่ขึ้นบรรทัดใหม่ ตอนนี้ฉันไม่มี Bash ที่สะดวกในการทดสอบ แต่คุณควรจะเขียนอะไรบางอย่างเช่น$STRING="${STRING/$'\n'/<br />}"
. (แม้ว่าคุณอาจต้องการSTRING//
- แทนที่ทั้งหมด - แทนที่จะเป็นเพียงSTRING/
)
echo ${my string foo/foo/bar}
คุณไม่สามารถทำ คุณต้องการinput="my string foo"; echo ${input/foo/bar}
//
โดยตรงมันกล่าวถึงสิ่งที่เกิดขึ้น "ถ้ารูปแบบเริ่มต้นด้วย ' /
'" (ซึ่งไม่แม่นยำแม้แต่เนื่องจากส่วนที่เหลือของประโยคนั้นถือว่าเป็นพิเศษ/
ไม่ใช่ส่วนหนึ่งของ รูปแบบ) - แต่ฉันไม่รู้แหล่งที่ดีกว่านี้
สามารถทำได้ทั้งหมดด้วยการจัดการสตริงทุบตี:
first="I love Suzy and Mary"
second="Sara"
first=${first/Suzy/$second}
สิ่งนั้นจะเข้ามาแทนที่เหตุการณ์แรกเท่านั้น หากต้องการแทนที่ทั้งหมดให้เพิ่มเครื่องหมายทับแรกเป็นสองเท่า:
first="Suzy, Suzy, Suzy"
second="Sara"
first=${first//Suzy/$second}
# first is now "Sara, Sara, Sara"
สำหรับ Dash โพสต์ก่อนหน้าทั้งหมดไม่ทำงาน
sh
โซลูชันที่รองรับPOSIX คือ:
result=$(echo "$firstString" | sed "s/Suzi/$secondString/")
result=$(echo $firstString | sed "s/Suzi/$secondString/g")
echo
อาร์กิวเมนต์ มันสามารถใช้งานได้โดยไม่ต้องพูดถึงกับสตริงที่เรียบง่าย แต่สามารถแยกสตริงอินพุตที่ไม่ใช่เรื่องง่าย (เว้นวรรคผิดปกติเชลล์เมตาอักขระ)
ลองนี้:
sed "s/Suzi/$secondString/g" <<<"$firstString"
จะดีกว่าsed
ถ้าใช้ bash มากกว่าถ้าสตริงมีอักขระ RegExp
echo ${first_string/Suzi/$second_string}
มันเป็นแบบพกพาไปยัง Windows และใช้งานได้กับ Bash 3.1 เป็นอย่างน้อย
เพื่อแสดงว่าคุณไม่ต้องกังวลกับการหลบหนีลองทำสิ่งนี้:
/home/name/foo/bar
เป็นนี้
~/foo/bar
แต่ถ้า/home/name
เป็นเพียงในการเริ่มต้น เราไม่ต้องการsed
!
เนื่องจาก bash นั้นทำให้เรามีตัวแปรเวทย์มนตร์$PWD
และ$HOME
เราสามารถ:
echo "${PWD/#$HOME/\~}"
แก้ไข:ขอบคุณสำหรับ Mark Haferkamp ในความคิดเห็นเพื่อทราบเกี่ยวกับการอ้างอิง / หลบหนี~
*
สังเกตว่าตัวแปร$HOME
มีเครื่องหมายสแลช แต่สิ่งนี้ไม่ทำลายอะไร
อ่านเพิ่มเติม: ขั้นสูงทุบตี Scripting คู่มือ
ถ้าใช้sed
เป็นต้องให้แน่ใจว่าได้หลบหนีตัวละครทุกตัว
sed
กับpwd
คำสั่งเพื่อหลีกเลี่ยงการกำหนดตัวแปรใหม่ทุกครั้งที่กำหนดเองของฉัน$PS1
ทำงาน Bash มีวิธีทั่วไปมากกว่าตัวแปรเวทเพื่อใช้เอาต์พุตของคำสั่งสำหรับการแทนที่สตริงหรือไม่? สำหรับโค้ดของคุณฉันต้องหลบเลี่ยง~
เพื่อป้องกัน Bash ไม่ให้ขยายเป็น $ HOME นอกจากนี้สิ่งที่#
อยู่ในคำสั่งของคุณจะทำอย่างไร
~
": สังเกตว่าฉันอ้างถึงสิ่งต่างๆอย่างไร จำไว้ว่าให้พูดทุกสิ่ง! และสิ่งนี้ไม่เพียงทำงานให้กับตัวแปรเวทย์มนตร์เท่านั้น: ตัวแปรใด ๆ ก็ตามที่สามารถทดแทนได้รับความยาวสตริงและอื่น ๆ อีกมากภายในการทุบตี ขอแสดงความยินดีที่คุณพยายาม$PS1
อย่างรวดเร็ว: คุณอาจสนใจ$PROMPT_COMMAND
ถ้าคุณคุ้นเคยกับภาษาการเขียนโปรแกรมอื่นและต้องการรหัสที่คอมไพล์แล้ว
echo "${PWD/#$HOME/~}"
ไม่ได้แทนฉันด้วย$HOME
~
แทนที่~
ด้วย\~
หรือ'~'
ทำงาน งานใด ๆ เหล่านี้ใน Bash 4.2.53 ใน distro อื่น คุณช่วยอัพเดทโพสต์ของคุณเพื่ออ้างหรือหลีกเลี่ยง~
เพื่อความเข้ากันได้ที่ดีขึ้นหรือไม่? สิ่งที่ฉันหมายถึงโดยคำถาม "ตัวแปรวิเศษ" ของฉันคือ: ฉันสามารถใช้การแทนที่ตัวแปรของ Bash เช่นผลลัพธ์ของuname
โดยไม่บันทึกเป็นตัวแปรเป็นอันดับแรกได้หรือไม่ ในฐานะที่เป็นส่วนบุคคลของฉัน$PROMPT_COMMAND
, มันซับซ้อน
ถ้าพรุ่งนี้คุณตัดสินใจว่าคุณไม่รักมารีรี่ย์เธอก็สามารถถูกแทนที่ด้วยเช่นกัน:
today=$(</tmp/lovers.txt)
tomorrow="${today//Suzi/Sara}"
echo "${tomorrow//Marry/Jesica}" > /tmp/lovers.txt
จะต้องมี 50 วิธีในการละทิ้งคู่รักของคุณ
เนื่องจากฉันไม่สามารถเพิ่มความคิดเห็น @ruaka เพื่อให้ตัวอย่างอ่านง่ายขึ้นเขียนเช่นนี้
full_string="I love Suzy and Mary"
search_string="Suzy"
replace_string="Sara"
my_string=${full_string/$search_string/$replace_string}
or
my_string=${full_string/Suzy/Sarah}
เพียวPOSIXวิธีเปลือกซึ่งแตกต่างจากโรมัน Kazanovskyi 's sed
คำตอบชั่นไม่จำเป็นต้องเครื่องมือภายนอกเพียงเปลือกของตัวเองพื้นเมืองขยายพารามิเตอร์ โปรดทราบว่าชื่อไฟล์แบบยาวจะย่อเล็กสุดเพื่อให้โค้ดพอดีกับหนึ่งบรรทัด:
f="I love Suzi and Marry"
s=Sara
t=Suzi
[ "${f%$t*}" != "$f" ] && f="${f%$t*}$s${f#*$t}"
echo "$f"
เอาท์พุท:
I love Sara and Marry
มันทำงานอย่างไร:
ลบรูปแบบคำต่อท้ายที่เล็กที่สุด "${f%$t*}"
ส่งคืน " I love
" ถ้าส่วนต่อท้าย$t
" Suzi*
" อยู่ใน$f
" " I love
Suzi and Marry
แต่ถ้าถ้าt=Zelda
เช่นนั้น"${f%$t*}"
จะไม่ลบอะไรเลยและส่งคืนสตริงทั้งหมด " I love Suzi and Marry
"
ใช้เพื่อทดสอบว่า$t
มีการ$f
ใช้งาน[ "${f%$t*}" != "$f" ]
ซึ่งจะประเมินเป็นจริงหาก$f
สตริงมี " Suzi*
" และเท็จถ้าไม่
หากการทดสอบส่งคืนค่าจริงสร้างสตริงที่ต้องการโดยใช้Remove Smallest Suffix Pattern ${f%$t*}
" I love
" และRemove Smallest Prefix Pattern ${f#*$t}
" and Marry
" โดยมีสตริงที่2$s
" Sara
" อยู่ระหว่างนั้น
ฉันรู้ว่ามันเก่า แต่เนื่องจากไม่มีใครพูดถึงการใช้ awk:
firstString="I love Suzi and Marry"
echo $firstString | awk '{gsub("Suzi","Sara"); print}'
echo [string] | sed "s/[original]/[target]/g"