Xóa một phần tử khỏi mảng Bash


116

Tôi cần xóa một phần tử khỏi một mảng trong bash shell. Nói chung tôi chỉ đơn giản là làm:

array=("${(@)array:#<element to remove>}")

Thật không may, phần tử tôi muốn loại bỏ là một biến nên tôi không thể sử dụng lệnh trước đó. Dưới đây là một ví dụ:

array+=(pluto)
array+=(pippo)
delete=(pluto)
array( ${array[@]/$delete} ) -> but clearly doesn't work because of {}

Bất kỳ ý tưởng?


Vỏ nào? Ví dụ của bạn trông như thế nào zsh.
chepner

array=( ${array[@]/$delete} )hoạt động như mong đợi trong Bash. Bạn chỉ đơn giản là bỏ lỡ =?
Ken Sharp

1
@Ken, đó không phải là điều bạn muốn - nó sẽ xóa bất kỳ kết quả phù hợp nào khỏi mỗi chuỗi và để lại các chuỗi trống trong mảng mà nó khớp với toàn bộ chuỗi.
Toby Speight

Câu trả lời:


165

Những điều sau đây hoạt động như bạn muốn bashzsh:

$ array=(pluto pippo)
$ delete=pluto
$ echo ${array[@]/$delete}
pippo
$ array=( "${array[@]/$delete}" ) #Quotes when working with strings

Nếu cần xóa nhiều hơn một phần tử:

...
$ delete=(pluto pippo)
for del in ${delete[@]}
do
   array=("${array[@]/$del}") #Quotes when working with strings
done

Cảnh báo trước

Kỹ thuật này thực sự loại bỏ các tiền tố so khớp $deletekhỏi các phần tử, không nhất thiết là toàn bộ các phần tử.

Cập nhật

Để thực sự xóa một mục chính xác, bạn cần xem qua mảng, so sánh mục tiêu với từng phần tử và sử dụng unsetđể xóa một đối sánh chính xác.

array=(pluto pippo bob)
delete=(pippo)
for target in "${delete[@]}"; do
  for i in "${!array[@]}"; do
    if [[ ${array[i]} = $target ]]; then
      unset 'array[i]'
    fi
  done
done

Lưu ý rằng nếu bạn làm điều này và một hoặc nhiều phần tử bị xóa, các chỉ số sẽ không còn là một chuỗi số nguyên liên tục nữa.

$ declare -p array
declare -a array=([0]="pluto" [2]="bob")

Thực tế đơn giản là, các mảng không được thiết kế để sử dụng làm cấu trúc dữ liệu có thể thay đổi. Chúng chủ yếu được sử dụng để lưu trữ danh sách các mục trong một biến đơn lẻ mà không cần lãng phí một ký tự làm dấu phân cách (ví dụ: để lưu trữ danh sách các chuỗi có thể chứa khoảng trắng).

Nếu khoảng trống là một vấn đề, thì bạn cần phải xây dựng lại mảng để lấp đầy khoảng trống:

for i in "${!array[@]}"; do
    new_array+=( "${array[i]}" )
done
array=("${new_array[@]}")
unset new_array

43
chỉ cần biết rằng: $ array=(sun sunflower) $ delete=(sun) $ echo ${array[@]/$delete}kết quả làflower
bernstein

12
Lưu ý rằng điều này thực sự đang thực hiện một sự thay thế, vì vậy nếu mảng giống như vậy (pluto1 pluto2 pippo)thì bạn sẽ kết thúc với (1 2 pippo).
haridsv

5
Chỉ cần cẩn thận khi sử dụng điều này trong vòng lặp for vì bạn sẽ kết thúc với một phần tử trống mà phần tử đã bị xóa. Đối với sự tỉnh táo của bạn có thể làm một cái gì đó giống nhưfor element in "${array[@]}" do if [[ $element ]]; then echo ${element} fi done
Joel B

2
Vậy làm thế nào để xóa chỉ các phần tử phù hợp?
UmaN

4
Lưu ý: điều này có thể đặt giá trị tương ứng thành không, nhưng phần tử sẽ vẫn nằm trong mảng.
phil294,

29

Bạn có thể tạo một mảng mới mà không có phần tử không mong muốn, sau đó gán nó trở lại mảng cũ. Điều này hoạt động trong bash:

array=(pluto pippo)
new_array=()
for value in "${array[@]}"
do
    [[ $value != pluto ]] && new_array+=($value)
done
array=("${new_array[@]}")
unset new_array

Điều này mang lại:

echo "${array[@]}"
pippo

14

Đây là cách trực tiếp nhất để bỏ đặt một giá trị nếu bạn biết vị trí của nó.

$ array=(one two three)
$ echo ${#array[@]}
3
$ unset 'array[1]'
$ echo ${array[@]}
one three
$ echo ${#array[@]}
2

3
Hãy thử echo ${array[1]}, bạn sẽ nhận được chuỗi null. Và để có được threebạn cần phải làm echo ${array[2]}. Vì vậy, unsetkhông phải là cơ chế phù hợp để loại bỏ một phần tử trong mảng bash.
rashok

@rashok, không, ${array[1]+x}là chuỗi rỗng, vì vậy array[1]không được đặt. unsetkhông làm thay đổi chỉ số của các phần tử còn lại. Trích dẫn đối số cho unset là không cần thiết. Cách để hủy một phần tử mảng được mô tả trong sách hướng dẫn Bash .
jarno

@rashok Tôi không hiểu tại sao không. Bạn không thể cho rằng điều đó ${array[1]}tồn tại chỉ vì kích thước là 2. Nếu bạn muốn các chỉ số, hãy kiểm tra ${!array[@]}.
Daniel C. Sobral

4

Đây là giải pháp một dòng với mapfile:

$ mapfile -d $'\0' -t arr < <(printf '%s\0' "${arr[@]}" | grep -Pzv "<regexp>")

Thí dụ:

$ arr=("Adam" "Bob" "Claire"$'\n'"Smith" "David" "Eve" "Fred")

$ echo "Size: ${#arr[*]} Contents: ${arr[*]}"

Size: 6 Contents: Adam Bob Claire
Smith David Eve Fred

$ mapfile -d $'\0' -t arr < <(printf '%s\0' "${arr[@]}" | grep -Pzv "^Claire\nSmith$")

$ echo "Size: ${#arr[*]} Contents: ${arr[*]}"

Size: 5 Contents: Adam Bob David Eve Fred

Phương thức này cho phép sự linh hoạt cao bằng cách sửa đổi / trao đổi lệnh grep và không để lại bất kỳ chuỗi trống nào trong mảng.


1
Hãy sử dụng printf '%s\n' "${array[@]}"thay vì điều xấu xí IFS/ echođiều đó.
gniourf_gniourf

Lưu ý rằng điều này không thành công với các trường chứa dòng mới.
gniourf_gniourf

@Socowi Bạn không chính xác, ít nhất là dựa trên cơ sở 4.4.19. -d $'\0'hoạt động hoàn toàn tốt trong khi chỉ cần -dkhông có đối số thì không.
Niklas Holm

À vâng, tôi đã trộn nó. Lấy làm tiếc. Ý tôi là: -d $'\0'giống như -d $'\0 something'hoặc chỉ -d ''.
Socowi

Không làm tổn thương để sử dụng $'\0'cho rõ ràng mặc dù
Niklas Holm

4

Câu trả lời này dành riêng cho trường hợp xóa nhiều giá trị khỏi mảng lớn, nơi hiệu suất là quan trọng.

Các giải pháp được bình chọn nhiều nhất là (1) thay thế mẫu trên một mảng hoặc (2) lặp qua các phần tử của mảng. Đầu tiên là nhanh, nhưng chỉ có thể xử lý các phần tử có tiền tố riêng biệt, thứ hai có O (n * k), n = kích thước mảng, k = phần tử cần loại bỏ. Mảng liên kết là tính năng tương đối mới và có thể không phổ biến khi câu hỏi được đăng ban đầu.

Đối với trường hợp đối sánh chính xác, với n và k lớn, có thể cải thiện hiệu suất từ ​​O (n k) thành O (n + k log (k)). Trong thực tế, O (n) giả sử k thấp hơn n nhiều. Hầu hết việc tăng tốc dựa trên việc sử dụng mảng kết hợp để xác định các mục cần xóa.

Hiệu suất (kích thước mảng n, k-giá trị để xóa). Hiệu suất đo giây thời gian của người dùng

   N     K     New(seconds) Current(seconds)  Speedup
 1000   10     0.005        0.033             6X
10000   10     0.070        0.348             5X
10000   20     0.070        0.656             9X
10000    1     0.043        0.050             -7%

Như dự đoán, nghiệm currentlà tuyến tính với N * K, và fastnghiệm thực tế là tuyến tính đối với K, với hằng số thấp hơn nhiều. Các fastgiải pháp là hơi chậm so với cáccurrent giải pháp khi k = 1, do cài đặt bổ sung.

Giải pháp 'Nhanh': mảng = danh sách đầu vào, xóa = danh sách giá trị cần loại bỏ.

        declare -A delk
        for del in "${delete[@]}" ; do delk[$del]=1 ; done
                # Tag items to remove, based on
        for k in "${!array[@]}" ; do
                [ "${delk[${array[$k]}]-}" ] && unset 'array[k]'
        done
                # Compaction
        array=("${array[@]}")

Được đánh giá so với currentgiải pháp, từ câu trả lời được bình chọn nhiều nhất.

    for target in "${delete[@]}"; do
        for i in "${!array[@]}"; do
            if [[ ${array[i]} = $target ]]; then
                unset 'array[i]'
            fi
        done
    done
    array=("${array[@]}")

3

Đây là một hàm nhỏ (có thể là rất cụ thể) liên quan đến chuyển hướng biến bash và unset; đó là một giải pháp chung không liên quan đến việc thay thế văn bản hoặc loại bỏ các phần tử trống và không có vấn đề với trích dẫn / khoảng trắng, v.v.

delete_ary_elmt() {
  local word=$1      # the element to search for & delete
  local aryref="$2[@]" # a necessary step since '${!$2[@]}' is a syntax error
  local arycopy=("${!aryref}") # create a copy of the input array
  local status=1
  for (( i = ${#arycopy[@]} - 1; i >= 0; i-- )); do # iterate over indices backwards
    elmt=${arycopy[$i]}
    [[ $elmt == $word ]] && unset "$2[$i]" && status=0 # unset matching elmts in orig. ary
  done
  return $status # return 0 if something was deleted; 1 if not
}

array=(a 0 0 b 0 0 0 c 0 d e 0 0 0)
delete_ary_elmt 0 array
for e in "${array[@]}"; do
  echo "$e"
done

# prints "a" "b" "c" "d" in lines

Sử dụng nó như thế delete_ary_elmt ELEMENT ARRAYNAMEnào mà không có bất kỳ $dấu hiệu nào . Chuyển == $wordcho == $word*các trận đấu tiền tố; sử dụng ${elmt,,} == ${word,,}cho các trận đấu không phân biệt chữ hoa chữ thường; vv, bất cứ điều gì bash [[hỗ trợ.

Nó hoạt động bằng cách xác định các chỉ số của mảng đầu vào và lặp lại chúng ngược lại (vì vậy việc xóa các phần tử không làm rối loạn thứ tự lặp lại). Để lấy các chỉ số, bạn cần truy cập vào mảng đầu vào theo tên, có thể được thực hiện thông qua chuyển hướng biến bash x=1; varname=x; echo ${!varname} # prints "1".

Bạn không thể truy cập các mảng theo tên như aryname=a; echo "${$aryname[@]}, điều này gây ra lỗi cho bạn. Bạn không thể làm aryname=a; echo "${!aryname[@]}"điều này, điều này cung cấp cho bạn các chỉ số của biến aryname(mặc dù nó không phải là một mảng). Công việc của DOES là gì aryref="a[@]"; echo "${!aryref}", sẽ in các phần tử của mảng a, bảo toàn phần trích dẫn từ shell và khoảng trắng chính xác như thế echo "${a[@]}". Nhưng điều này chỉ hoạt động để in các phần tử của một mảng chứ không phải để in độ dài hoặc chỉ số của nó ( aryref="!a[@]"hoặc aryref="#a[@]"hoặc "${!!aryref}"hoặc "${#!aryref}", tất cả chúng đều không thành công).

Vì vậy, tôi sao chép mảng ban đầu theo tên của nó thông qua chuyển hướng bash và lấy các chỉ số từ bản sao. Để lặp lại ngược lại các chỉ số, tôi sử dụng vòng lặp for kiểu C. Tôi cũng có thể làm điều đó bằng cách truy cập các chỉ số thông qua ${!arycopy[@]}và đảo ngược chúng với tac, đó là một catbiến xung quanh thứ tự dòng đầu vào.

Một giải pháp hàm mà không có biến hướng có thể sẽ phải liên quan eval, có thể có hoặc có thể không an toàn để sử dụng trong tình huống đó (tôi không thể nói).


Điều này gần như hoạt động tốt, tuy nhiên nó không khai báo lại mảng ban đầu được truyền vào hàm, vì vậy trong khi mảng ban đầu đó bị thiếu giá trị, nó cũng có các chỉ mục của nó bị xáo trộn. Điều này có nghĩa là lệnh gọi tiếp theo mà bạn thực hiện để xóa_ary_elmt trên cùng một mảng sẽ không hoạt động (hoặc sẽ loại bỏ những thứ sai). Ví dụ: sau những gì bạn đã dán, hãy thử chạy delete_ary_elmt "d" arrayvà sau đó in lại mảng. Bạn sẽ thấy rằng phần tử sai sẽ bị loại bỏ. Việc xóa phần tử cuối cùng cũng sẽ không bao giờ hoạt động.
Scott

2

Để mở rộng các câu trả lời ở trên, bạn có thể sử dụng cách sau để xóa nhiều phần tử khỏi một mảng mà không cần so khớp từng phần:

ARRAY=(one two onetwo three four threefour "one six")
TO_REMOVE=(one four)

TEMP_ARRAY=()
for pkg in "${ARRAY[@]}"; do
    for remove in "${TO_REMOVE[@]}"; do
        KEEP=true
        if [[ ${pkg} == ${remove} ]]; then
            KEEP=false
            break
        fi
    done
    if ${KEEP}; then
        TEMP_ARRAY+=(${pkg})
    fi
done
ARRAY=("${TEMP_ARRAY[@]}")
unset TEMP_ARRAY

Điều này sẽ dẫn đến một mảng chứa: (hai một hai ba ba phần bốn "một sáu")



1

Chỉ trả lời một phần

Để xóa mục đầu tiên trong mảng

unset 'array[0]'

Để xóa mục cuối cùng trong mảng

unset 'array[-1]'

@gniourf_gniourf không cần sử dụng dấu ngoặc kép cho đối số của unset.
jarno

2
@jarno: các dấu ngoặc kép này PHẢI được sử dụng: nếu bạn có một tệp có tên array0trong thư mục hiện tại, thì vì array[0]là tệp cầu, nên trước tiên nó sẽ được mở rộng array0trước lệnh unset.
gniourf_gniourf

@gniourf_gniourf bạn nói đúng. Điều này nên được sửa chữa trong Sổ tay Tham khảo Bash hiện nói rằng "chưa đặt tên [chỉ số dưới] hủy phần tử mảng tại chỉ số dưới chỉ mục".
jarno

1

Sử dụng unset

Để loại bỏ một phần tử tại chỉ mục cụ thể, chúng ta có thể sử dụng unsetvà sau đó sao chép sang một mảng khác. Chỉ unsetlà không cần thiết trong trường hợp này. Bởi vì unsetkhông loại bỏ phần tử, nó chỉ đặt chuỗi null thành chỉ số cụ thể trong mảng.

declare -a arr=('aa' 'bb' 'cc' 'dd' 'ee')
unset 'arr[1]'
declare -a arr2=()
i=0
for element in "${arr[@]}"
do
    arr2[$i]=$element
    ((++i))
done
echo "${arr[@]}"
echo "1st val is ${arr[1]}, 2nd val is ${arr[2]}"
echo "${arr2[@]}"
echo "1st val is ${arr2[1]}, 2nd val is ${arr2[2]}"

Đầu ra là

aa cc dd ee
1st val is , 2nd val is cc
aa cc dd ee
1st val is cc, 2nd val is dd

Sử dụng :<idx>

Chúng tôi cũng có thể loại bỏ một số tập hợp các phần tử bằng cách sử dụng :<idx>. Ví dụ, nếu chúng ta muốn loại bỏ phần tử thứ nhất, chúng ta có thể sử dụng :1như được đề cập bên dưới.

declare -a arr=('aa' 'bb' 'cc' 'dd' 'ee')
arr2=("${arr[@]:1}")
echo "${arr2[@]}"
echo "1st val is ${arr2[1]}, 2nd val is ${arr2[2]}"

Đầu ra là

bb cc dd ee
1st val is cc, 2nd val is dd

0

Tập lệnh shell POSIX không có mảng.

Vì vậy, hầu hết có thể bạn đang sử dụng một phương ngữ cụ thể như bash, korn shellzsh .

Do đó, câu hỏi của bạn đến thời điểm hiện tại vẫn chưa thể trả lời được.

Có thể điều này phù hợp với bạn:

unset array[$delete]

2
Xin chào, tôi đang sử dụng bash shell atm. Và "$ delete" không phải là vị trí của phần tử mà là chính chuỗi. Vì vậy, tôi không nghĩ rằng "unset" sẽ hoạt động
Alex

0

Trên thực tế, tôi chỉ nhận thấy rằng cú pháp shell phần nào có một hành vi được tích hợp sẵn cho phép dễ dàng xây dựng lại mảng khi, như được đặt ra trong câu hỏi, một mục cần được xóa.

# let's set up an array of items to consume:
x=()
for (( i=0; i<10; i++ )); do
    x+=("$i")
done

# here, we consume that array:
while (( ${#x[@]} )); do
    i=$(( $RANDOM % ${#x[@]} ))
    echo "${x[i]} / ${x[@]}"
    x=("${x[@]:0:i}" "${x[@]:i+1}")
done

Chú ý cách chúng ta xây dựng mảng bằng x+=()cú pháp của bash ?

Bạn thực sự có thể thêm nhiều mục cùng với đó, nội dung của toàn bộ mảng khác cùng một lúc.


0

http://wiki.bash-hackers.org/syntax/pe#substring_removal

$ {PARAMETER # PATTERN} # xóa từ đầu

$ {PARAMETER ## PATTERN} # xóa ngay từ đầu, khớp tham lam

$ {PARAMETER% PATTERN} # xóa khỏi phần cuối

$ {PARAMETER %% PATTERN} # xóa khỏi phần cuối, đối sánh tham lam

Để thực hiện một phần tử loại bỏ hoàn toàn, bạn phải thực hiện lệnh hủy đặt với câu lệnh if. Nếu bạn không quan tâm đến việc xóa tiền tố khỏi các biến khác hoặc về việc hỗ trợ khoảng trắng trong mảng, thì bạn có thể bỏ dấu ngoặc kép và quên vòng lặp for.

Xem ví dụ bên dưới để biết một số cách khác nhau để dọn dẹp một mảng.

options=("foo" "bar" "foo" "foobar" "foo bar" "bars" "bar")

# remove bar from the start of each element
options=("${options[@]/#"bar"}")
# options=("foo" "" "foo" "foobar" "foo bar" "s" "")

# remove the complete string "foo" in a for loop
count=${#options[@]}
for ((i = 0; i < count; i++)); do
   if [ "${options[i]}" = "foo" ] ; then
      unset 'options[i]'
   fi
done
# options=(  ""   "foobar" "foo bar" "s" "")

# remove empty options
# note the count variable can't be recalculated easily on a sparse array
for ((i = 0; i < count; i++)); do
   # echo "Element $i: '${options[i]}'"
   if [ -z "${options[i]}" ] ; then
      unset 'options[i]'
   fi
done
# options=("foobar" "foo bar" "s")

# list them with select
echo "Choose an option:"
PS3='Option? '
select i in "${options[@]}" Quit
 do
    case $i in 
       Quit) break ;;
       *) echo "You selected \"$i\"" ;;
    esac
 done

Đầu ra

Choose an option:
1) foobar
2) foo bar
3) s
4) Quit
Option? 

Hy vọng rằng sẽ giúp.


0

Trong ZSH, điều này rất dễ xảy ra (lưu ý rằng điều này sử dụng nhiều cú pháp tương thích với bash hơn mức cần thiết nếu có thể để dễ hiểu):

# I always include an edge case to make sure each element
# is not being word split.
start=(one two three 'four 4' five)
work=(${(@)start})

idx=2
val=${work[idx]}

# How to remove a single element easily.
# Also works for associative arrays (at least in zsh)
work[$idx]=()

echo "Array size went down by one: "
[[ $#work -eq $(($#start - 1)) ]] && echo "OK"

echo "Array item "$val" is now gone: "
[[ -z ${work[(r)$val]} ]] && echo OK

echo "Array contents are as expected: "
wanted=("${start[@]:0:1}" "${start[@]:2}")
[[ "${(j.:.)wanted[@]}" == "${(j.:.)work[@]}" ]] && echo "OK"

echo "-- array contents: start --"
print -l -r -- "-- $#start elements" ${(@)start}
echo "-- array contents: work --"
print -l -r -- "-- $#work elements" "${work[@]}"

Các kết quả:

Array size went down by one:
OK
Array item two is now gone:
OK
Array contents are as expected:
OK
-- array contents: start --
-- 5 elements
one
two
three
four 4
five
-- array contents: work --
-- 4 elements
one
three
four 4
five

Xin lỗi, chỉ cần thử. Nó đã không làm việc trong zsh cho một mảng assoziative
Falk

Nó hoạt động tốt, tôi chỉ cần thử nghiệm nó (một lần nữa). Những điều không hiệu quả với bạn? Vui lòng giải thích những gì không hoạt động chính xác và chi tiết nhất có thể. Bạn đang sử dụng phiên bản ZSH nào?
trevorj

0

Cũng có cú pháp này, ví dụ: nếu bạn muốn xóa phần tử thứ 2:

array=("${array[@]:0:1}" "${array[@]:2}")

mà trên thực tế là sự ghép nối của 2 tab. Đầu tiên từ chỉ số 0 đến chỉ mục 1 (độc quyền) và thứ 2 từ chỉ số 2 đến cuối.


-1

Những gì tôi làm là:

array="$(echo $array | tr ' ' '\n' | sed "/itemtodelete/d")"

BAM, mục đó đã bị xóa.


1
Điều này phá vỡ cho array=('first item' 'second item').
Benjamin W.

-1

Đây là một giải pháp nhanh chóng và hiệu quả sẽ hoạt động trong các trường hợp đơn giản nhưng sẽ bị $deletehỏng nếu (a) có các ký tự đặc biệt regex trong hoặc (b) có bất kỳ khoảng trắng nào trong bất kỳ mục nào. Bắt đầu với:

array+=(pluto)
array+=(pippo)
delete=(pluto)

Xóa tất cả các mục nhập khớp chính xác $delete:

array=(`echo $array | fmt -1 | grep -v "^${delete}$" | fmt -999999`)

dẫn đến echo $array-> pippo và đảm bảo rằng đó là một mảng: echo $array[1]-> pippo

fmthơi tối nghĩa: fmt -1bao bọc ở cột đầu tiên (để đặt mỗi mục trên dòng riêng của nó. Đó là nơi vấn đề nảy sinh với các mục trong khoảng trắng.) fmt -999999mở nó trở lại một dòng, đặt lại khoảng cách giữa các mục. Có những cách khác để làm điều đó, chẳng hạn như xargs.

Phụ lục: Nếu bạn chỉ muốn xóa trận đấu đầu tiên, hãy sử dụng sed, như được mô tả ở đây :

array=(`echo $array | fmt -1 | sed "0,/^${delete}$/{//d;}" | fmt -999999`)

-1

Làm thế nào về một cái gì đó như:

array=(one two three)
array_t=" ${array[@]} "
delete=one
array=(${array_t// $delete / })
unset array_t

-1

Để tránh xung đột với chỉ số mảng sử dụng unset- xem https://stackoverflow.com/a/49626928/3223785https://stackoverflow.com/a/47798640/3223785 để biết thêm thông tin - phân công lại mảng với bản thân: ARRAY_VAR=(${ARRAY_VAR[@]}).

#!/bin/bash

ARRAY_VAR=(0 1 2 3 4 5 6 7 8 9)
unset ARRAY_VAR[5]
unset ARRAY_VAR[4]
ARRAY_VAR=(${ARRAY_VAR[@]})
echo ${ARRAY_VAR[@]}
A_LENGTH=${#ARRAY_VAR[*]}
for (( i=0; i<=$(( $A_LENGTH -1 )); i++ )) ; do
    echo ""
    echo "INDEX - $i"
    echo "VALUE - ${ARRAY_VAR[$i]}"
done

exit 0

[Tham khảo: https://tecadmin.net/working-with-array-bash-script/ ]


-2
#/bin/bash

echo "# define array with six elements"
arr=(zero one two three 'four 4' five)

echo "# unset by index: 0"
unset -v 'arr[0]'
for i in ${!arr[*]}; do echo "arr[$i]=${arr[$i]}"; done

arr_delete_by_content() { # value to delete
        for i in ${!arr[*]}; do
                [ "${arr[$i]}" = "$1" ] && unset -v 'arr[$i]'
        done
        }

echo "# unset in global variable where value: three"
arr_delete_by_content three
for i in ${!arr[*]}; do echo "arr[$i]=${arr[$i]}"; done

echo "# rearrange indices"
arr=( "${arr[@]}" )
for i in ${!arr[*]}; do echo "arr[$i]=${arr[$i]}"; done

delete_value() { # value arrayelements..., returns array decl.
        local e val=$1; new=(); shift
        for e in "${@}"; do [ "$val" != "$e" ] && new+=("$e"); done
        declare -p new|sed 's,^[^=]*=,,'
        }

echo "# new array without value: two"
declare -a arr="$(delete_value two "${arr[@]}")"
for i in ${!arr[*]}; do echo "arr[$i]=${arr[$i]}"; done

delete_values() { # arraydecl values..., returns array decl. (keeps indices)
        declare -a arr="$1"; local i v; shift
        for v in "${@}"; do 
                for i in ${!arr[*]}; do
                        [ "$v" = "${arr[$i]}" ] && unset -v 'arr[$i]'
                done
        done
        declare -p arr|sed 's,^[^=]*=,,'
        }
echo "# new array without values: one five (keep indices)"
declare -a arr="$(delete_values "$(declare -p arr|sed 's,^[^=]*=,,')" one five)"
for i in ${!arr[*]}; do echo "arr[$i]=${arr[$i]}"; done

# new array without multiple values and rearranged indices is left to the reader

1
Bạn có thể thêm một số nhận xét hoặc mô tả để cho chúng tôi biết về câu trả lời của bạn không?
Michael
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.