153

bash シェルで配列から要素を削除する必要があります。一般的に私は単に行うだろう:

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

残念ながら、削除したい要素は変数なので、前のコマンドは使用できません。以下に例を示します。

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

何か案が?

4

20 に答える 20

233

bash以下は、およびで必要に応じて機能しますzsh

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

複数の要素を削除する必要がある場合:

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

警告

$deleteこの手法は、必ずしも要素全体ではなく、要素から一致する接頭辞を実際に削除します。

アップデート

完全に一致するアイテムを実際に削除するには、配列を調べて、ターゲットを各要素と比較し、 を使用unsetして完全一致を削除する必要があります。

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

これを行い、1 つ以上の要素が削除されると、インデックスは整数の連続シーケンスではなくなることに注意してください。

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

単純な事実は、配列は変更可能なデータ構造として使用するように設計されていないということです。これらは主に、区切り文字として文字を無駄にすることなく、単一の変数にアイテムのリストを格納するために使用されます (たとえば、空白を含む可能性のある文字列のリストを格納するため)。

ギャップが問題になる場合は、アレイを再構築してギャップを埋める必要があります。

for i in "${!array[@]}"; do
    new_array+=( "${array[i]}" )
done
array=("${new_array[@]}")
unset new_array
于 2013-05-31T16:33:04.420 に答える
5

mapfile を使用した 1 行のソリューションを次に示します。

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

例:

$ 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

この方法では、grep コマンドを変更/交換することで柔軟性が大幅に向上し、配列に空の文字列が残りません。

于 2016-10-26T13:46:48.457 に答える
2

上記の回答を拡張するには、以下を使用して、部分一致なしで配列から複数の要素を削除できます。

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

これにより、以下を含む配列が得られます: (two onetwo three threefour "one six")

于 2016-03-16T09:48:06.467 に答える
2

set -e または set -x の値を記憶し、それらを復元できるようにする必要がある場合は、最初の配列削除ソリューションを使用して独自のスタックを管理するこの要点を確認してください。

https://gist.github.com/kigster/94799325e39d2a227ef89676eed44cc6

于 2019-12-24T22:04:39.577 に答える
0

実際、シェル構文には、質問で提起されたように、アイテムを削除する必要がある場合に、配列を簡単に再構築できる動作が組み込まれていることに気付きました。

# 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

bash のx+=()構文を使用して配列を作成した方法に注目してください。

実際には、他の配列全体のコンテンツを一度に複数のアイテムを追加できます。

于 2016-12-21T07:20:37.393 に答える
0

POSIX シェル スクリプトには配列がありません。

そのため、おそらくbash、korn シェル、またはzsh.

したがって、現時点でのご質問にはお答えできません。

多分これはあなたのために働く:

unset array[$delete]
于 2013-05-31T15:38:45.850 に答える
0

ZSH では、これは非常に簡単です (理解を容易にするために、必要以上に bash と互換性のある構文を使用していることに注意してください)。

# 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[@]}"

結果:

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
于 2016-04-09T10:11:30.980 に答える
-1

私がすることは:

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

BAM、そのアイテムは削除されました。

于 2016-05-24T17:13:48.863 に答える
-1

$deleteこれは、単純なケースでは機能するが、(a) に正規表現の特殊文字がある場合、または (b) いずれかの項目にスペースがまったくない場合に機能しない、簡単で汚いソリューションです。で始まります:

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

に完全に一致するすべてのエントリを削除します$delete

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

結果は echo $array-> pippo になり、それが配列であることを確認します: echo $array[1]-> pippo

fmtは少しあいまいです:最初の列で折り返さfmt -1れます (各項目を独自の行に配置するためです。スペース内の項目で問題が発生する場所です) 。fmt -999999など、他の方法もありますxargs

補遺: 最初の一致のみを削除する場合は、次のように sed を使用します

array=(`echo $array | fmt -1 | sed "0,/^${delete}$/{//d;}" | fmt -999999`)
于 2016-11-01T14:16:57.127 に答える