Đối với bash , đó là một chút hack (mặc dù được ghi lại): cố gắng sử dụng typeset
để xóa thuộc tính "mảng":
$ typeset +a BASH_VERSINFO
bash: typeset: BASH_VERSINFO: cannot destroy array variables in this way
echo $?
1
(Bạn không thể thực hiện việc này zsh
, nó cho phép bạn chuyển đổi một mảng thành vô hướng, trong bash
đó rõ ràng là bị cấm.)
Vì thế:
typeset +A myvariable 2>/dev/null || echo is assoc-array
typeset +a myvariable 2>/dev/null || echo is array
Hoặc trong một chức năng, lưu ý các cảnh báo ở cuối:
function typeof() {
local _myvar="$1"
if ! typeset -p $_myvar 2>/dev/null ; then
echo no-such
elif ! typeset -g +A $_myvar 2>/dev/null ; then
echo is-assoc-array
elif ! typeset -g +a $_myvar 2>/dev/null; then
echo is-array
else
echo scalar
fi
}
Lưu ý việc sử dụng typeset -g
(bash-4.2 trở lên), điều này là bắt buộc trong một chức năng để typeset
(đồng bộ declare
) không hoạt động như thế local
và ghi đè lên giá trị bạn đang cố kiểm tra. Điều này cũng không xử lý các loại chức năng "biến", bạn có thể thêm một thử nghiệm chi nhánh khác bằng cách sử dụng typeset -f
nếu cần.
Một tùy chọn khác (gần hoàn thành) là sử dụng:
${!name[*]}
If name is an array variable, expands to the list
of array indices (keys) assigned in name. If name
is not an array, expands to 0 if name is set and
null otherwise. When @ is used and the expansion
appears within double quotes, each key expands to a
separate word.
Tuy nhiên, có một vấn đề nhỏ, một mảng có một chỉ số 0 phù hợp với hai trong số các điều kiện trên. Đây là điều mà mikeerv cũng tham khảo, bash thực sự không có sự phân biệt khó khăn và một số điều này (nếu bạn kiểm tra Changelog) có thể bị đổ lỗi cho ksh và tương thích với cách ${name[*]}
hoặc${name[@]}
hành xử trên một mảng không.
Vì vậy, một giải pháp một phần là:
if [[ ${!BASH_VERSINFO[*]} == '' ]]; then
echo no-such
elif [[ ${!BASH_VERSINFO[*]} == '0' ]]; then
echo not-array
elif [[ ${!BASH_VERSINFO[*]} != '0' ]];
echo is-array
fi
Tôi đã sử dụng trong quá khứ một biến thể về điều này:
while read _line; do
if [[ $_line =~ ^"declare -a" ]]; then
...
fi
done < <( declare -p )
điều này cũng cần một subshell mặc dù.
Một kỹ thuật hữu ích hơn có thể là compgen
:
compgen -A arrayvar
Điều này sẽ liệt kê tất cả các mảng được lập chỉ mục, tuy nhiên các mảng kết hợp không được xử lý đặc biệt (tối đa bash-4.4) và xuất hiện dưới dạng các biến thông thường ( compgen -A variable
)