Làm thế nào để có được một giá trị biến nếu tên biến được lưu dưới dạng chuỗi?


142

Làm cách nào tôi có thể truy xuất giá trị biến bash nếu tôi có tên biến là chuỗi?

var1="this is the real value"
a="var1"
Do something to get value of var1 just using variable a.

Bối cảnh:

Tôi có một số AMI ( Hình ảnh máy Amazon ) và tôi muốn kích hoạt một vài trường hợp của mỗi AMI. Ngay sau khi họ khởi động xong, tôi muốn thiết lập từng phiên bản theo loại AMI của nó. Tôi không muốn nướng nhiều tập lệnh hoặc khóa bí mật bên trong bất kỳ AMI nào vì vậy tôi đã chuẩn bị một tập lệnh khởi động tổng quát và tôi đưa nó lên S3 với một liên kết có thể truy cập công khai. Trong RC.local, tôi đặt một đoạn mã nhỏ để tìm nạp tập lệnh khởi động và thực thi nó. Đây là tất cả những gì tôi có trong AMIs. Sau đó, mỗi AMI truy cập một tập lệnh cấu hình chung áp dụng cho tất cả các AMI và tập lệnh thiết lập đặc biệt cho mỗi tập lệnh. Các tập lệnh này là riêng tư và yêu cầu một URL đã ký để truy cập chúng.

Vì vậy, bây giờ, khi tôi kích hoạt một phiên bản của AMI (my_private_ami_1), tôi chuyển một URL đã ký cho một tệp khác được trình bày trên S3 có chứa URL được ký cho tất cả các tập lệnh riêng theo cặp khóa / giá trị.

config_url="http://s3.amazo.../config?signature"
my_private_ami_1="http://s3.amazo.../ami_1?signature"
...
Khi tập lệnh khởi động chạy, nó tải tập tin ở trên và là tập tin sourceđó. Sau đó, nó kiểm tra loại AMI của nó và chọn tập lệnh thiết lập chính xác cho chính nó.

ami\_type=GET AMI TYPE #ex: sets ami\_type to my\_private\_ami\_1
setup\_url=GET THE SETUP FILE URL BASED ON AMI\_TYPE # this is where this problem arises

Vì vậy, bây giờ tôi có thể có một mã chung có thể kích hoạt các thể hiện bất kể các loại AMI của chúng và các thể hiện có thể tự chăm sóc chúng.

Câu trả lời:


257

Bạn có thể sử dụng ${!a}:

var1="this is the real value"
a="var1"
echo "${!a}" # outputs 'this is the real value'

Đây là một ví dụ về mở rộng tham số gián tiếp :

Các hình thức cơ bản của mở rộng tham số là ${parameter}. Giá trị của parameterđược thay thế.

Nếu ký tự đầu tiên của parameterlà một dấu chấm than (!), Nó sẽ đưa ra một mức độ không xác định. Bash sử dụng giá trị của biến được hình thành từ phần còn lại parameterlàm tên của biến; biến này sau đó được mở rộng và giá trị đó được sử dụng trong phần còn lại của sự thay thế, thay vì giá trị của parameterchính nó.


4
Điều này làm việc cho tôi trong OSX bash, nhưng không phải là debian? Trên debian tôi nhận được Bad substitutionlỗi.
23

11
@ 23inhouse Bạn đang chạy tập lệnh của mình bằng cách sử dụng /bin/sh? Nếu vậy, hãy thử sử dụng /bin/bashthay thế. Từ Debian Squeeze trở đi, /bin/shđã được thay đổi thành một liên kết tượng trưng dashthay chobash . dashkhông hỗ trợ cú pháp cụ thể này và sẽ xuất ra Bad substitutionlỗi.
Phil Ross

8
Có cách nào để làm cho công việc này cho một tên biến thuộc về một mảng không?
Loupax

Hoạt động trên Ubuntu với bash
Sergey P. aka azure

1
@DoronShai Đây là một ví dụ về mở rộng tham số gián tiếp, được ghi lại trong Tài liệu tham khảo Bash tại gnu.org/software/bash/manual/html_node/
Phil Ross

29
X=foo
Y=X
eval "Z=\$$Y"

đặt Z thành "foo"

Hãy cẩn thậneval khi sử dụng vì điều này có thể cho phép loại bỏ mã chính thức thông qua các giá trị trong ${Y}. Điều này có thể gây hại thông qua tiêm mã.

Ví dụ

Y="\`touch /tmp/eval-is-evil\`"

sẽ tạo ra /tmp/eval-is-evil. Điều này cũng có thể là một số rm -rf /, tất nhiên.


đã cứu cái đuôi của tôi, ty
raffian

9

Sửa đổi từ khóa tìm kiếm của tôi và có nó :).

eval a=\$$a
Cảm ơn vì đã dành thời gian cho tôi.


Hãy cẩn thận khi sử dụng eval vì điều này có thể cho phép loại bỏ mã chính thức thông qua các giá trị trong ${Y}. Xem bổ sung của tôi trong câu trả lời của người dùng "anon".
thử-bắt-cuối cùng

Đây là câu trả lời duy nhất làm việc. Trớ trêu rằng đó là của riêng bạn!
Ctrl S

8

Đối với người dùng zsh đồng nghiệp của tôi, cách để thực hiện điều tương tự như câu trả lời được chấp nhận là sử dụng:

${(P)a}

Nó được gọi là thay thế tên tham số

Điều này buộc giá trị của tên tham số được hiểu là tên tham số tiếp theo, giá trị của nó sẽ được sử dụng khi thích hợp. Lưu ý rằng các cờ được thiết lập với một trong các nhóm lệnh (đặc biệt là các phép biến đổi) không được áp dụng cho giá trị của tên được sử dụng theo kiểu này.

Nếu được sử dụng với tham số lồng nhau hoặc thay thế lệnh, kết quả của nó sẽ được lấy làm tên tham số theo cùng một cách. Ví dụ: nếu bạn có 'foo = bar' và 'bar = baz', các chuỗi $ {(P) foo}, $ {(P) $ {foo}} và $ {(P) $ (thanh echo) } sẽ được mở rộng thành 'baz'.

Tương tự, nếu tham chiếu được lồng chính nó, biểu thức với cờ được xử lý như thể nó được thay thế trực tiếp bằng tên tham số. Đó là một lỗi nếu sự thay thế lồng nhau này tạo ra một mảng có nhiều hơn một từ. Ví dụ: nếu 'name = assoc' trong đó tham số assoc là một mảng kết hợp, thì '$ {$ {(P) name} [elt]}' đề cập đến phần tử của liên kết được đăng ký 'elt'.


0

shell hiện đại đã hỗ trợ mảng (và thậm chí cả mảng kết hợp). Vì vậy, xin vui lòng sử dụng chúng, và sử dụng ít eval.

var1="this is the real value"
array=("$var1")
# or array[0]="$var1"

sau đó khi bạn muốn gọi nó, echo $ {mảng [0]}


điều này sẽ làm việc nếu tôi nhận được chuỗi từ đối số dòng lệnh (ví dụ như $1)?
jena

0

Dựa trên câu trả lời: https://unix.stackexchange.com/a/111627

###############################################################################
# Summary: Returns the value of a variable given it's name as a string.
# Required Positional Argument: 
#   variable_name - The name of the variable to return the value of
# Returns: The value if variable exists; otherwise, empty string ("").
###############################################################################
get_value_of()
{
    variable_name=$1
    variable_value=""
    if set | grep -q "^$variable_name="; then
        eval variable_value="\$$variable_name"
    fi
    echo "$variable_value"
}

test=123
get_value_of test
# 123
test="\$(echo \"something nasty\")"
get_value_of test
# $(echo "something nasty")

0

Có cùng một vấn đề với mảng, đây là cách thực hiện nếu bạn cũng thao tác với mảng:

array_name="ARRAY_NAME"
ARRAY_NAME=("Val0" "Val1" "Val2")

ARRAY=$array_name[@]
echo "ARRAY=${ARRAY}"
ARRAY=("${!ARRAY}")
echo "ARRAY=${ARRAY[@]}"
echo "ARRAY[0]=${ARRAY[0]}"
echo "ARRAY[1]=${ARRAY[1]}"
echo "ARRAY[2]=${ARRAY[2]}"

Điều này sẽ xuất ra:

ARRAY=ARRAY_NAME[@]
ARRAY=Val0 Val1 Val2
ARRAY[0]=Val0
ARRAY[1]=Val1
ARRAY[2]=Val2
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.