Trong bash
vỏ, ${!var}
là một biến đổi không định hướng. Nó mở rộng đến giá trị của biến có tên được giữ trong đó $var
.
Mở rộng biến ${var+value}
là một mở rộng POSIX mở rộng đến value
nếu biến var
được đặt (bất kể giá trị của nó có trống hay không).
Kết hợp những thứ này, ${!var+x}
sẽ mở rộng thành x
nếu biến có tên được giữ trong đó $var
được đặt.
Thí dụ:
$ foo=hello
$ var=foo
$ echo "${!var+$var is set, its value is ${!var}}"
foo is set, its value is hello
$ unset foo
$ echo "${!var+$var is set, its value is ${!var}}"
(dòng trống là đầu ra)
Hàm trong câu hỏi có thể rút ngắn thành
check_if_variable_is_set () { [ -n "${!1+x}" ]; }
hoặc thậm chí:
check_if_variable_is_set () { [ -v "$1" ]; }
hoặc thậm chí:
check_if_variable_is_set()[[ -v $1 ]]
Trong trường hợp -v
là một bash
thử nghiệm trên một tên biến mà sẽ là true nếu biến có tên được thiết lập, và sai khác.
POSIXly, nó có thể được viết:
check_if_variable_is_set() { eval '[ -n "${'"$1"'+x}" ]'; }
Lưu ý rằng tất cả chúng là các lỗ hổng tiêm lệnh tiềm năng nếu đối số của hàm đó có thể bị kiểm soát bởi kẻ tấn công. Hãy thử ví dụ với check_if_variable_is_set 'a[$(id>&2)]'
.
Để bảo vệ chống lại điều đó, trước tiên bạn có thể muốn xác minh rằng đối số là tên biến hợp lệ. Đối với các biến:
check_if_variable_is_set() {
case $1 in
("" | *[![:alnum:]_]* | [![:alpha:]_]*) false;;
(*) eval '[ -n "${'"$1"'+x}" ]'
esac
}
(lưu ý rằng [[:alpha:]]
sẽ kiểm tra các ký tự chữ cái trong ngôn ngữ của bạn trong khi một số shell chỉ chấp nhận các ký tự chữ cái từ bộ ký tự di động trong biến của chúng)