เป็นไปได้ไหมที่จะพิมพ์เนื้อหาของเนื้อหาของตัวแปรด้วย shell script? (การอ้างอิงทางอ้อม)


13

สมมุติว่าฉันประกาศตัวแปรต่อไปนี้แล้ว:

$ var='$test'
$ test="my string"

หากฉันพิมพ์เนื้อหาของพวกเขาฉันเห็นดังต่อไปนี้:

$ echo $var
$test

$ echo $test
my string

ฉันต้องการหาวิธีพิมพ์เนื้อหาของเนื้อหาของ$var(ซึ่งเป็นเนื้อหาของ$test) ดังนั้นฉันจึงพยายามทำสิ่งต่อไปนี้:

$ echo $(echo $var)
$test

แต่นี่คือผลลัพธ์$testและไม่ใช่"my string"... เป็นไปได้หรือไม่ที่จะพิมพ์เนื้อหาของตัวแปรโดยใช้ bash?


คุณสามารถแก้ไขโพสต์ของคุณเพื่อบอกว่าคุณใช้เชลล์ตัวไหนหรือคุณต้องการความสามารถในการพกพาแบบไหน?
Michael Homer

@MichaelHomer แน่นอน แต่ฉันจะตรวจสอบข้อมูลนี้ได้อย่างไร
Rafael Muynarsk

มันเป็นสิ่งที่คุณเลือกมากกว่าที่จะตรวจสอบ ตัวอย่างเช่นคุณใช้งานสคริปต์ของคุณด้วยash, หรือbash, หรือcsh, หรือdash, ... , หรือzsh, หรือ POSIX shหรือคุณต้องการทำงานข้ามระบบต่าง ๆ หรือไม่?
Michael Homer

@MichaelHomer อาฉันเห็น ... ฉันใช้ทุบตี ฉันจะเปลี่ยนคำถามสุดท้ายและใส่แท็กใหม่แล้ว
Rafael Muynarsk

คำตอบ:


21

คุณสามารถทำได้โดยใช้การขยายตัวแปรทางอ้อมของ bash (ตราบใดที่มันโอเคสำหรับคุณที่จะไม่ใช้$ตัวแปรการอ้างอิงของคุณ):

$ var=test
$ test="my string"
$ echo "$var"
test
$ echo "${!var}"
my string

3.5.3 การขยายพารามิเตอร์เชลล์


10

สำหรับกรณีที่ชื่อตัวแปรที่อยู่ในvarนั้นนำหน้าด้วย$คุณอาจใช้eval:

$ var='$test'
$ test="my string"
$ eval echo $var
my string

เกิดอะไรขึ้นที่นี่:

  • bash ขยาย$varไปยังค่า$test, สร้างeval echo $testคำสั่ง;
  • evalประเมินecho $testการแสดงออกและสร้างผลลัพธ์ที่ต้องการ

โปรดทราบว่าการใช้โดยevalทั่วไปอาจเป็นอันตราย (ขึ้นอยู่กับสิ่งที่เก็บไว้var) ดังนั้นควรหลีกเลี่ยง คุณลักษณะการขยายทางอ้อมจะดีกว่าสำหรับกรณีของคุณ (แต่คุณต้องกำจัดการ$ลงชื่อเข้าใช้$test)


แน่นอนว่านั่นเป็นพิมพ์ผิด โพสต์ต้นฉบับมีคำพูดเดียว แก้ไขแล้ว.
Danila Kiver

4
ฉันมักจะแนะนำการอ้างอิงตัวแปรการอ้างอิงสองครั้ง (เพื่อหลีกเลี่ยงปัญหาจากการแยกคำที่ไม่คาดคิดและการขยายสัญลักษณ์แทน) ด้วยคุณจะต้องสองชั้นของราคาสองบรรทัดนี้:eval eval echo "\"$var\""โปรดทราบว่าสิ่งนี้ไม่ได้ทำอะไรเกี่ยวกับอันตรายอื่น ๆ ของการใช้evalที่คุณกล่าวถึง
Gordon Davisson

9

คล้ายกับคำตอบของ Jesse_bแต่ใช้ตัวแปรอ้างอิงชื่อแทนการเปลี่ยนทิศทาง (ต้องการbash4.3+):

$ declare -n var=test
$ test="my string"
$ echo "$var"
my string

ตัวแปรอ้างอิงชื่อvarถือชื่อของตัวแปรที่อ้างอิง เมื่อตัวแปรถูกอ้างอิงเป็น$varค่าของตัวแปรอื่นจะถูกส่งกลับ

bash แก้ไขการอ้างอิงชื่อแบบเรียกซ้ำ:

$ declare -n var1=var2
$ declare -n var2=test
$ test="hello world"
$ echo "$var1"
hello world

เพื่อความสมบูรณ์การใช้อาเรย์แบบเชื่อมโยง (ในbash4.0+) เป็นวิธีหนึ่งในการแก้ไขปัญหานี้ขึ้นอยู่กับข้อกำหนด:

$ declare -A strings
$ strings[test]="my string"
$ var=test
$ echo "${strings[$var]}"
my string

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


3

ด้วยzsh:

$ var='$test'
$ test='*'
$ printf '%s\n' ${(e)var}
*

กับทุกเชลล์บอร์นเหมือน

$ eval 'printf "%s\n" "'"$var"'"'
*

โปรดจำไว้ว่าในการขยายตัวแปรหอยเหล่านั้นจะต้องยกมาเพื่อป้องกันการแยก + glob ( zshเป็นข้อยกเว้น) และechoไม่สามารถใช้สำหรับข้อมูลโดยพลการ

เนื่องจากมีทั้ง(e)และevalมีการประเมินรหัสเชลล์สิ่งสำคัญคือเนื้อหาที่$varอยู่ในการควบคุมของคุณเป็นอย่างอื่นที่อาจเป็นช่องโหว่การฉีดคำสั่งโดยพลการ (เช่นเดียวกับ${!var}วิธีการ)

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