การแทนที่คำสั่งสามารถซ้อนในการแทนที่ตัวแปรได้หรือไม่?


10

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

$ xclip -o -selection clipboard
Here's a string I just copied.

หากฉันกำหนดให้กับตัวแปรดังนั้นฉันสามารถทำการทดแทนตัวแปรได้

$ var=$(xclip -o -selection clipboard)
$ echo $var
Here's a string I just copied.
$ echo ${var/copi/knott}
Here's a string I just knotted.

อย่างไรก็ตามมีวิธีการเปลี่ยนตัวแปรโดยไม่ต้องกำหนดให้กับตัวแปรหรือไม่? แนวคิดบางอย่างเช่นนี้

$ echo ${$(xclip -o -selection clipboard)/copi/knott}
bash: ${$(xclip -o -selection clipboard)/copi/knott}: bad substitution

ไวยากรณ์นี้ล้มเหลวเนื่องจากvarควรเป็นชื่อตัวแปรไม่ใช่สตริง

คำตอบ:


6

ไม่คุณไม่สามารถ bashและเชลล์อื่น ๆ ส่วนใหญ่ (ยกเว้นzsh) ไม่อนุญาตการทดแทนที่ซ้อนกัน

ด้วยzshคุณสามารถทำการทดแทนที่ซ้อนกัน :

$ echo ${$(echo 123)/123/456}   
456

bashฉันจะยอมรับคำตอบนี้เพราะมันมีบางส่วนหลักฐานว่ามันเป็นไปไม่ได้ใน (และผลักฉันอีกครั้งเพื่อการโยกย้ายไปzsh.)
Sparhawk

2

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

v=; echo "${v:=${0##*["$0${v:=$(xsel -bo)}"]}${v/copi/knott}}"

ฉันใช้การ$0ขยายพารามิเตอร์ภายในห่วงโซ่เพื่อซ่อนการมอบหมาย มันกำหนดค่าของ var ภายในการขยายการกำหนดที่ซ้อนกัน ด้านนอกมีความสำคัญกว่า - แต่เพราะมันจะขยายไปถึงสิ่งที่ด้านในทำยากที่จะบอก อย่างไรก็ตามหากเราปิดเสียงการขยายตัวด้านในให้แก้ไขมันคุณจะได้รับสิ่งที่คุณต้องการ หลังจากคัดลอกสตริงของคุณไปยังคลิปบอร์ดของฉัน(ฉันไม่มีxclip- เพียงแค่xsel)มันพิมพ์:

Here's a string I just knotted.

มันชัดเจนขึ้นเล็กน้อยว่าเกิดอะไรขึ้นถ้าคุณออก$0ไปแม้ว่า:

v=; echo "${v:=${v:=$(xsel -bo)}${v/copi/knott}}"

ภาพพิมพ์นั้น:

Here's a string I just copied.  Here's a string I just knotted.

... เนื่องจากการมอบหมายภายในเกิดขึ้นก่อนการปรับเปลี่ยน แต่ตามที่ระบุไว้การมอบหมายภายนอกจะมีความสำคัญกว่าและจะขยายไปสู่การขยายภายในของการมอบหมายภายใน และการปรับเปลี่ยนภายใน

แน่นอนว่าไม่มีการทำงานใด ๆ เลยหากกำหนดพารามิเตอร์เป้าหมายไว้แล้ว - ดังนั้นคุณสามารถทำได้แน่นอนถ้าคุณล้างตัวแปรในตอนแรก ... ซึ่งโดยสุจริตอาจเป็นเวลาที่สะดวกที่สุดในการกำหนดมันหลังจากทั้งหมด .


+1 สำหรับวิธีแก้ปัญหาแม้ว่าอย่างที่คุณพูดมันเป็นวิธีแก้ปัญหาที่อาจแย่กว่าการกำหนดตัวแปร!
Sparhawk

@Sparhawk - ใช่แน่นอนแย่ลง และก็ไม่มีอะไรผิดปกติที่มีอยู่แล้ว - ไม่มีอะไรมากที่จะได้รับยกเว้นความไม่แน่นอน คุณสามารถหาaliasทางอ้อมเพื่อทำให้สะดวกขึ้นเล็กน้อย - แต่ถ้ามันคุ้มกับคุณคุณควรตั้งค่าฟังก์ชั่นสำหรับจัดการการอ้างอิงอย่างปลอดภัยและทำบางสิ่งด้วยevalกัน w / eval- หากคุณสามารถสร้างตัวอักษรแรกของจำนวนเอาต์พุตย่อยของคำสั่งไปยังไวยากรณ์ส่วนขยายที่ใช้การได้ - จากนั้นคุณอาจจะได้รับมากขึ้นอีกมากง่ายขึ้น ฉันรู้ว่าสิ่งนี้จะง่าย w / xsel- ใช้ stdin - แต่xsel?
mikeserv

@Sparhawk - ฉันรู้วิธีการทำอย่างใดอย่างหนึ่งเท่านั้นเพราะในบางสถานการณ์มันจะมีประโยชน์ - เช่นการขยายที่พร้อมท์หรือที่นี่ doc - ซึ่งคุณไม่สามารถรับการมอบหมายเชลล์ในปัจจุบันเพื่อนำไปใช้เป็นอย่างอื่นได้
mikeserv

1

หากคุณไม่ต้องการสร้างตัวแปร aa มีวิธีอื่นในการดำเนินการทดแทนสตริง:

$ echo $(xclip -o -selection clipboard | sed 's/copi/knott/')
Here's a string I just knotted.

ขอบคุณฉันรู้ว่าฉันสามารถใช้sedแทนได้ แต่มันก็เป็นคำถามทั่วไปเกี่ยวกับการวางซ้อนของการแทนที่
Sparhawk

@Sparhawk สำหรับความรู้ของฉันไม่มีใครสามารถทดแทนตัวแปรได้โดยไม่ต้องมีตัวแปร
John1024

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

@Sparhawk ดีมาก
John1024

+1 แต่ฉันจะยอมรับคำตอบอื่นเนื่องจากมีหลักฐานที่เป็นรูปธรรมมากขึ้นเล็กน้อยว่ามันไม่ได้ผลในการทุบตี
Sparhawk
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.