แทนที่สตริงในเชลล์สคริปต์โดยใช้ตัวแปร


94

ฉันใช้โค้ดด้านล่างเพื่อแทนที่สตริงภายในเชลล์สคริปต์

echo $LINE | sed -e 's/12345678/"$replace"/g'

แต่มันถูกแทนที่ด้วย$replaceแทนค่าของตัวแปรนั้น

มีใครบอกได้ไหมว่าเกิดอะไรขึ้น?


สำหรับคำถามที่เกี่ยวข้องทั่วไปเกี่ยวกับการจัดการกับค่าที่มีเครื่องหมายทับโปรดดูstackoverflow.com/questions/5864146/use-slashes-in-sed-replace
tripleee

คำตอบ:


147

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

ลอง:

echo $LINE | sed -e "s/12345678/\"${replace}\"/g"

สมมติว่าคุณต้องการใส่เครื่องหมายคำพูดหากคุณไม่ต้องการคำพูดให้ใช้:

echo $LINE | sed -e "s/12345678/${replace}/g"

การถอดเสียง:

pax> export replace=987654321
pax> echo X123456789X | sed "s/123456789/${replace}/"
X987654321X
pax> _

เพียงระมัดระวังเพื่อให้แน่ใจว่า${replace}ไม่มีอักขระใด ๆ ที่มีความสำคัญsed(เช่น/เช่น) เนื่องจากจะทำให้เกิดความสับสนเว้นแต่จะหลีกหนี แต่ถ้าอย่างที่คุณบอกว่าคุณกำลังแทนที่หมายเลขหนึ่งด้วยหมายเลขอื่นก็ไม่น่าจะเป็นปัญหา


ฉันไม่ต้องการใส่เครื่องหมายคำพูดฉันต้องการให้ตัวเลขหนึ่งถูกแทนที่ด้วยหมายเลขอื่น
Vijay

1
paxdiablo: setก็ไม่จำเป็นเช่นกัน (แล้วคุณจะใช้มันอย่างไร?) เพียงreplace=987654321.
Roman Cheplyaka

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

โซลูชันนี้ดูเหมือนจะใช้ไม่ได้กับ-iตัวเลือกนี้ คุณจะรู้ว่าทำไม? หรือจะทำให้มันทำงานได้อย่างไร?
Gabriel

1
นอกจากนี้ยังอาจชี้ให้เห็นว่าการเปลี่ยนจากเครื่องหมายคำพูดเดี่ยวเป็นคำพูดคู่จำเป็นต้องมีเครื่องหมายใด ๆ$หรือ`ในsedสคริปต์ที่จะหลีกเลี่ยงด้วยแบ็กสแลชเพื่อป้องกันจากกลไกการแทนที่ของเชลล์สำหรับสตริงที่ยกมาสองครั้ง
tripleee

74

คุณสามารถใช้เชลล์ (bash / ksh)

$ var="12345678abc"
$ replace="test"
$ echo ${var//12345678/$replace}
testabc

3
อาจต้องการพูดถึง bash-specific (และ ksh?) อาจจะไม่ได้นำเข้าเพื่อคนส่วนใหญ่ แต่บางส่วนของเรายังคงบังคับให้ทำงานใน UNIXen โบราณ :-)
paxdiablo

6
ระวังสิ่งนี้ล้มเหลวในการรีบซึ่งอยู่/bin/shใน Linuxes ที่ทันสมัยจำนวนมาก
phihag

28

ไม่เฉพาะเจาะจงสำหรับคำถาม แต่สำหรับผู้ที่ต้องการฟังก์ชั่นประเภทเดียวกันขยายเพื่อความชัดเจนจากคำตอบก่อนหน้า

# create some variables
str="someFileName.foo"
find=".foo"
replace=".bar"
# notice the the str isn't prefixed with $
#    this is just how this feature works :/
result=${str//$find/$replace}
echo $result    
# result is: someFileName.bar

str="someFileName.sally"
find=".foo"
replace=".bar"
result=${str//$find/$replace}
echo $result    
# result is: someFileName.sally because ".foo" was not found


8

คำคมโสดมาแรงมาก เมื่อเข้าไปข้างในแล้วคุณไม่สามารถทำอะไรได้เพื่อเรียกใช้การแทนที่ตัวแปรจนกว่าคุณจะออกไป ใช้เครื่องหมายคำพูดคู่แทน:

echo $LINE | sed -e "s/12345678/$replace/g"

4
echo $LINE | sed -e 's/12345678/'$replace'/g'

คุณยังสามารถใช้อัญประกาศเดี่ยวได้ แต่คุณต้อง "เปิด" เมื่อคุณต้องการให้ตัวแปรขยายในตำแหน่งที่ถูกต้อง มิฉะนั้นจะใช้สตริง "ตามตัวอักษร" (ตามที่ @paxdiablo ระบุไว้อย่างถูกต้องคำตอบของเขาก็ถูกต้องเช่นกัน)


สิ่งนี้มีปัญหาว่าการใช้$replaceนอกเครื่องหมายคำพูดใด ๆ จะทำให้เชลล์ดำเนินการเว้นวรรคโทเค็นและการขยายสัญลักษณ์แทนค่า สิ่งนี้ดูเหมือนจะใช้งานได้กับค่าที่เรียบง่าย แต่สามารถระเบิดได้อย่างมากในสตริงที่ไม่สำคัญ อย่าใช้สิ่งนี้ในรหัสการผลิต
tripleee

2

เพื่อให้เชลล์ของคุณขยายตัวแปรคุณต้องใช้เครื่องหมายคำพูดคู่เช่น

sed -i "s#12345678#$replace#g" file.txt

สิ่งนี้จะแตกหาก$replaceมีsedอักขระพิเศษ( #, \) แต่คุณสามารถประมวลผลล่วงหน้า$replaceเพื่ออ้างถึง:

replace_quoted=$(printf '%s' "$replace" | sed 's/[#\]/\\\0/g')
sed -i "s#12345678#$replace_quoted#g" file.txt

0

ฉันมีข้อกำหนดที่คล้ายกันนี้ แต่การแทนที่ var ของฉันมีเครื่องหมายแอมเพอร์แซนด์ การหลีกเลี่ยงเครื่องหมายและวิธีนี้ช่วยแก้ปัญหาของฉัน:

replace="salt & pepper"
echo "pass the salt" | sed "s/salt/${replace/&/\&}/g"

-1

ใช้สิ่งนี้แทน

echo $LINE | sed -e 's/12345678/$replace/g'

สิ่งนี้ใช้ได้กับฉันเพียงแค่ลบคำพูด


-2

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

ดังนั้นให้ใช้เครื่องหมายคำพูดคู่

echo $LINE | sed -e "s/12345678/$replace/g"

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