Có thể in nội dung của một biến với shell script? (tham chiếu gián tiếp)


13

Giả sử tôi đã khai báo các biến sau:

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

Nếu tôi in nội dung của họ, tôi thấy như sau:

$ echo $var
$test

$ echo $test
my string

Tôi muốn tìm một cách để in nội dung của nội dung $var(đó là nội dung của $test). Vì vậy, tôi đã cố gắng làm như sau:

$ echo $(echo $var)
$test

Nhưng đây là kết quả $testvà không "my string"... Có thể in nội dung của các biến bằng bash không?


Bạn có thể chỉnh sửa bài đăng của mình để nói bạn đang sử dụng shell nào, hoặc bạn có yêu cầu về tính di động nào không?
Michael Homer

@MichaelHomer Chắc chắn, nhưng chính xác làm thế nào tôi có thể kiểm tra thông tin này?
Rafael Muynarsk

Đó là một cái gì đó mà bạn chọn hơn là một cái gì đó để kiểm tra. Ví dụ: bạn đang chạy tập lệnh của mình với ash, hoặc bash, cshhoặc dash, ..., hoặc zsh, hoặc POSIX sh, hoặc bạn có cần phải làm việc trên các hệ thống khác nhau không?
Michael Homer

@MichaelHomer À, tôi hiểu rồi ... Tôi đang sử dụng bash. Tôi sẽ chỉ thay đổi câu hỏi cuối cùng và chèn một thẻ mới sau đó.
Rafael Muynarsk

Câu trả lời:


21

Bạn có thể thực hiện việc này bằng cách sử dụng mở rộng biến gián tiếp của bash (miễn là bạn có thể loại bỏ $biến tham chiếu của mình):

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

3.5.3 Mở rộng tham số Shell


10

Đối với trường hợp khi tên biến chứa trong vartiền tố $bạn có thể sử dụng eval:

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

Chuyện gì xảy ra ở đây thế:

  • bash mở rộng $varđến giá trị $test, tạo ra một eval echo $testlệnh;
  • evalđánh giá echo $testbiểu thức và tạo ra một kết quả mong muốn.

Lưu ý rằng việc sử dụng evalnói chung có thể nguy hiểm (tùy thuộc vào những gì được lưu trữ trong var), vì vậy nên tránh sử dụng nó. Tính năng mở rộng gián tiếp sẽ tốt hơn cho trường hợp của bạn (nhưng bạn cần phải thoát khỏi $đăng nhập $test).


Chắc chắn, đó là một loại nhầm. Các bài viết gốc có dấu ngoặc đơn. Đã sửa.
Danila Kiver

4
Tôi luôn đề xuất các tham chiếu biến trích dẫn kép (để tránh rắc rối từ việc tách từ không mong muốn và mở rộng ký tự đại diện). Với eval, bạn cần hai lớp dấu ngoặc kép, dòng này : eval echo "\"$var\"". Nhắc bạn, điều này không làm bất cứ điều gì về những nguy hiểm khác của việc sử dụng evalmà bạn đã đề cập.
Gordon Davisson

9

Tương tự như câu trả lời của Jesse_b , nhưng sử dụng biến tham chiếu tên thay vì chỉ định biến (yêu cầu bash4.3+):

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

Biến tham chiếu tên vargiữ tên của biến mà nó tham chiếu. Khi biến được hủy đăng ký $var, giá trị của biến khác được trả về.

bash giải quyết các tham chiếu tên đệ quy:

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

Để hoàn thiện, sử dụng một mảng kết hợp (trong bash4.0+) cũng là một cách để giải quyết điều này, tùy thuộc vào yêu cầu:

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

Điều này cung cấp một cách linh hoạt hơn để truy cập nhiều hơn một giá trị bằng một khóa hoặc tên có thể được xác định động. Điều này có thể thích hợp hơn nếu bạn muốn thu thập tất cả các giá trị của một danh mục cụ thể trong một mảng, nhưng vẫn có thể truy cập chúng bằng một số khóa (ví dụ: tên có thể truy cập bằng ID hoặc tên đường dẫn có thể truy cập theo mục đích, v.v.) vì nó không gây ô nhiễm không gian tên biến của tập lệnh.


3

Với zsh:

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

Với bất kỳ vỏ giống như Bourne

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

Hãy nhớ rằng trong các shell đó, các mở rộng biến phải được trích dẫn để ngăn chia + global ( zshlà một ngoại lệ) và echokhông thể được sử dụng cho dữ liệu tùy ý.

Vì với cả hai (e)evalcó đánh giá mã shell, điều quan trọng là nội dung của $varbạn nằm trong tầm kiểm soát của bạn vì nếu không đó có thể là một lỗ hổng tiêm lệnh tùy ý (giống với các ${!var}phương pháp tiếp cận).

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.