Làm thế nào để bỏ tập hợp phạm vi của mảng trong Bash


8

Tôi đang cố gắng xóa phạm vi của phần tử mảng nhưng không thành công ..

Mảng của tôi

root@ubuntu:~/work# echo ${a[@]}
cocacola.com airtel.com pepsi.com

In mảng 0-1 có vẻ ổn

root@ubuntu:~/work# echo ${a[@]::2}
cocacola.com airtel.com

Bây giờ tôi đang cố gắng chỉ xóa các phần tử này bằng cách sử dụng:

root@ubuntu:~/work# unset a[@]::2
root@ubuntu:~/work# echo ${a[@]}

Nó xóa toàn bộ mảng ..

Tôi đang làm gì sai?

Tôi tìm thấy cách khác để xóa phạm vi của mảng nhưng tại sao những thứ trên không hoạt động?

for ((i=0; i<2; i++)); do unset a[$i]; done

EDIT tôi cũng đã thử nhưng không có may mắn

unset -v 'a[@]::2'

Câu trả lời:


14

Một điều cần lưu ý là bashcác mảng được triển khai như ksh, đó là các mảng kết hợp trong đó các khóa được giới hạn ở các số nguyên dương (trái với các ngôn ngữ khác như perlhoặc zshví dụ).

Trong:

a[123]=foo a[456]=bar a[789]=baz

Trong bash, bạn đã có một mảng kết hợp với 3 phần tử, trong khi đó perl, bạn sẽ có một mảng với 790 phần tử (789 với zsh).

Trong kshhoặc bash, ${a[@]:0:1}trả về phần tử đầu tiên của mảng trong danh sách các phần tử được sắp xếp theo số theo khóa trong đó khóa lớn hơn hoặc bằng 0. Vì vậy, trong trường hợp đó, nó trả về ${a[123]}, không ${a[0]}.

unset 'a[123]'

(hãy nhớ trích dẫn nó, nếu không sẽ thất bại nếu có một tệp có tên a1 hoặc a2 hoặc a3 trong thư mục hiện tại) có ý nghĩa, vì nó loại bỏ một khóa cụ thể trong mảng.

unset 'a[@]::2'

làm cho ít ý nghĩa hơn mặc dù. bashchỉ hiểu unset a, unset 'a[123]'hoặc unset 'a[*/@]', bất cứ điều gì sau khi bị bỏ qua, vì vậy unset 'a[@]::2'unset 'a[@]please'làm tương tự: bỏ đặt toàn bộ mảng.

Nếu bạn muốn hủy đặt một loạt các phím, bạn cần lặp qua các phím:

Để có được danh sách các khóa của mảng, cú pháp là "${!a[@]}". Thật không may, áp dụng một phạm vi cho điều đó không hoạt động với bashcũng không ksh, vì vậy bạn cần một mảng tạm thời:

keys=("${!a[@]}")
for i in "${keys[@]::2}"; do unset "a[$i]"; done

Bây giờ nếu bạn muốn xem xét các mảng như trong các ngôn ngữ khác, bạn không muốn sử dụng unset. Giống như, nếu mảng đầu tiên không thưa thớt và bạn muốn giữ nó như vậy (đó là thay đổi tất cả các phần tử bằng 2 thay vì bỏ chọn hai phần đầu), bạn có thể thực hiện những việc như:

a=("${a[@]:2}")

Đó là gán lại mảng với danh sách các yếu tố bạn muốn giữ.

Để so sánh, với zsh.

a=({1..20})
unset 'a[12,16]'

sẽ đặt một giá trị trống cho các phần tử 12 đến 16. trong khi unset 'a[16,20]'sẽ thu nhỏ mảng thành 15 phần tử.

a=({1..20})
a[12,16]=()

(vẫn với zsh) sẽ thay đổi các yếu tố 17 đến 20 bởi 5 vị trí a[12]sẽ chứa 17.


Cảm ơn .. bạn là chủ nhân của tôi ... với sự giúp đỡ của vấn đề này, tôi đã giải quyết được một vấn đề .. vì vậy xin vui lòng xem xét vấn đề này và cho tôi biết nếu có bất kỳ cải tiến nào trong Mã Bash đó .. unix.stackexchange.com/questions/74001/ Tiết
kiệm

1
  1. Nếu mảng của bạn liên tục / không thưa thớt (tất cả các yếu tố từ 0..N-1 bộ)

    Bạn có thể loại bỏ phần tử thứ 2 của mảng bằng

    unset 'a[1]'

    Để xóa phần tử thứ 2, 3 và 4, bạn có thể sử dụng, vd

    for ((i=1; i<=3; i++)); do unset "a[$i]"; done

    Để xóa tất cả trừ phần tử thứ 1 và thứ 2, bạn có thể sử dụng, vd

    for ((i=2; i<${#a[@]}; i++)); do unset "a[$i]"; done
  2. Giải pháp chung (cũng hoạt động đối với mảng thưa): Bạn có thể xóa phần tử thứ 2 của mảng bằng

    unset "a[$(echo ${!a[@]} | cut -d" " -f 2)]"

    Để xóa phần tử thứ 2, 3 và 4, bạn có thể sử dụng, vd

    for $(echo ${!a[@]} | cut -d" " -f 2-4) ; do unset "a[$i]"; done

    Để xóa tất cả trừ phần tử thứ 1 và thứ 2, bạn có thể sử dụng, vd

    for $(echo ${!a[@]} | cut -d" " -f 2-) ; do unset "a[$i]"; done

Tôi đã làm điều này n đã cập nhật trong câu hỏi .. nhưng câu hỏi vẫn còn vềunset a[@]::2
Rahul Patil

Điều đó sai trong trường hợp chung vì ${#a[@]}số lượng phần tử trong mảng, không phải là chỉ số lớn nhất trong mảng ( bashmảng, giống như kshmảng là thưa thớt, trái với các phần tử zsh).
Stéphane Chazelas

@StephaneChazelas sau khi xóa phần tử tại sao không thiết lập lại chỉ mục?
Rahul Patil

@StephaneChazelas sau khi thực hiện một số RnD Tôi đã tìm thấy cách này để thiết lập lại mảng a=( $(echo ${a[@]}) ) có ổn không?
Rahul Patil

2
@RahulPatil, nếu bạn muốn làm mờ mảng, chỉ cần viết nó : a=("${a[@]}"), sử dụng echovà thay thế lệnh sẽ chỉ hoạt động trong các trường hợp góc bị giới hạn (như khi không có phần tử nào trống hoặc chứa spc, tab, NL, dấu gạch chéo ngược, *,?, [hoặc bắt đầu bằng -).
Stéphane Chazelas
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.