Bash 배열에서 요소 제거
bash 셸의 배열에서 요소를 제거해야 합니다.일반적으로 다음과 같은 작업을 수행합니다.
array=("${(@)array:#<element to remove>}")
유감스럽게도 제거하려는 요소가 변수이므로 이전 명령을 사용할 수 없습니다.다음은 예입니다.
array+=(pluto)
array+=(pippo)
delete=(pluto)
array( ${array[@]/$delete} ) -> but clearly doesn't work because of {}
감 잡히는 게 없어요?
이 원하는 대로 작동합니다.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
이 작업을 수행하고 하나 이상의 요소가 제거되면 인덱스는 더 이상 연속적인 정수 시퀀스가 아닙니다.
$ 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
원하지 않는 요소 없이 새 배열을 작성한 다음 이전 배열에 다시 할당할 수 있습니다.이 기능은 다음에서 작동합니다.bash
:
array=(pluto pippo)
new_array=()
for value in "${array[@]}"
do
[[ $value != pluto ]] && new_array+=($value)
done
array=("${new_array[@]}")
unset new_array
이는 다음과 같습니다.
echo "${array[@]}"
pippo
이 방법은 위치를 알고 있는 경우 값을 설정 해제하는 가장 직접적인 방법입니다.
$ array=(one two three)
$ echo ${#array[@]}
3
$ unset 'array[1]'
$ echo ${array[@]}
one three
$ echo ${#array[@]}
2
이 답변은 성능이 중요한 대규모 어레이에서 여러 값을 삭제하는 경우에만 적용됩니다.
가장 많이 사용되는 솔루션은 (1) 배열에 대한 패턴 대체 또는 (2) 배열 요소에 대한 반복입니다.첫 번째는 빠르지만 접두사가 다른 요소만 처리할 수 있고, 두 번째는 O(n*k), n=array size, k=제거할 요소를 가집니다.연관 배열은 상대적으로 새로운 기능이며, 질문이 처음 게시되었을 때 일반적이지 않았을 수 있습니다.
n과 k가 큰 정확한 일치 사례의 경우 O(nk)에서 O(n+klog(k))로 성능을 향상시킬 수 있습니다.실제로는 O(n)가 n보다 k를 훨씬 더 낮게 가정합니다.대부분의 속도 향상은 연관 배열을 사용하여 제거할 항목을 식별하는 것을 기준으로 합니다.
성능(n-배열 크기, 삭제할 k-값).사용자 시간의 성능 측정(초)
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%
시역.current
은 N이며, 솔션은 N*K에선며,fast
솔루션은 훨씬 낮은 상수로 K에 실질적으로 선형입니다. 그fast
솔루션은 솔루션에 비해 약간 느립니다.current
k=1일 때 솔루션, 추가 설정으로 인해.
빠른' 솔루션: array=입력 목록, delete=제거할 값 목록.
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[@]}")
벤마크에 대한 current
해결책, 가장 중요한 답변으로부터.
for target in "${delete[@]}"; do
for i in "${!array[@]}"; do
if [[ ${array[i]} = $target ]]; then
unset 'array[i]'
fi
done
done
array=("${array[@]}")
맵 파일이 포함된 한 줄 솔루션은 다음과 같습니다.
$ 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 명령을 수정/교환하여 유연성을 높일 수 있으며 배열에 빈 문자열을 남기지 않습니다.
부분적인 답변만
배열의 첫 번째 항목을 삭제하려면 다음과 같이 하십시오.
unset 'array[0]'
배열의 마지막 항목을 삭제하려면 다음과 같이 하십시오.
unset 'array[-1]'
위의 답변을 확장하려면 다음을 사용하여 부분 일치 없이 배열에서 여러 요소를 제거할 수 있습니다.
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
이것은 다음을 포함하는 배열을 생성합니다: (2 1 2 3 4 "1 6")
과 bash (아마도 bash에 bash와 입니다.unset
텍스트 대체나 빈 요소 폐기가 필요 없는 일반적인 솔루션으로, 인용/오류 공간 등에 문제가 없습니다.
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
럼사용처럼 합니다.delete_ary_elmt ELEMENT ARRAYNAME
것도 없이$
. 스위치를 켭니다.== $word
위해서== $word*
일치의 ; 접사일치경우의; 사용두를 합니다.${elmt,,} == ${word,,}
/소문자를 하지 않는 일치 항목 bash "/" "/" "" "" "" "" "" " " ""[[
지원합니다.
이는 입력 배열의 인덱스를 결정하고 요소를 삭제해도 반복 순서가 흐트러지지 않도록 역방향으로 반복하는 방식으로 작동합니다. 하며, variable direction을 수 . bash는 bash의 인덱스입니다.x=1; varname=x; echo ${!varname} # prints "1"
.
다음과 같은 이름으로 어레이에 액세스할 수 없습니다.aryname=a; echo "${$aryname[@]}
이것은 당신에게 오류를 줍니다.은 할 수 요.aryname=a; echo "${!aryname[@]}"
수 있습니다.aryname
(어레이는 아니지만).가 있는 은 작하는것입니다.aryref="a[@]"; echo "${!aryref}"
가 인쇄됩니다.a
하는 것이 좋습니다.echo "${a[@]}"
됩니다.aryref="!a[@]"
또는aryref="#a[@]"
또는"${!!aryref}"
또는"${#!aryref}"
모두 실패합니다.
그래서 저는 bash indirection을 통해 원래 배열을 이름으로 복사하고 복사본에서 인덱스를 가져옵니다.역방향 인덱스를 반복하기 위해 루프에 C 스타일을 사용합니다.또한 다음을 통해 인덱스에 액세스할 수 있습니다.${!arycopy[@]}
로 뒤집어서 리고그역전것는키시을들그▁and▁them것▁reversing.tac
은 즉, 즉입니다.cat
입력 라인 순서를 돌립니다.
방향성에 대한 변수가 없는 함수 솔루션은 아마도 다음과 같이 포함되어야 할 것입니다.eval
그 상황에서 사용하는 것이 안전할 수도 있고 안전하지 않을 수도 있습니다(알 수 없습니다.
용사를 합니다.unset
하려면 특인덱에요제소면다사용다니합음을려거하정서를스다▁at▁to니를 하면 됩니다.unset
그런 다음 다른 배열로 복사합니다. ㅠㅠunset
이 경우에는 필요하지 않습니다. ㅠㅠunset
배열의 특정 인덱스에 null 문자열만 설정하는 요소는 제거하지 않습니다.
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]}"
출력은
aa cc dd ee
1st val is , 2nd val is cc
aa cc dd ee
1st val is cc, 2nd val is dd
용사를 합니다.:<idx>
다음을 사용하여 요소 집합을 제거할 수 있습니다.:<idx>
첫 요소를 하려면 한또를 . 예를 들어 첫 번째 요소를 제거하려는 경우 사용할 수 있습니다.:1
하기와 같이
declare -a arr=('aa' 'bb' 'cc' 'dd' 'ee')
arr2=("${arr[@]:1}")
echo "${arr2[@]}"
echo "1st val is ${arr2[1]}, 2nd val is ${arr2[2]}"
출력은
bb cc dd ee
1st val is cc, 2nd val is dd
http://wiki.bash-hackers.org/syntax/pe#substring_removal
${PARAMETER#PATTERN}# 처음부터 제거
${PARAMETER##PATTERN}# 처음부터 제거, 탐욕스러운 일치
${PARAMETER%PATTERN}# 끝에서 제거
${PARAMETER%%PATTERNAL} 끝에서 제거, 탐욕스러운 일치
전체 제거 요소를 수행하려면 if 문을 사용하여 설정 해제 명령을 수행해야 합니다.다른 변수에서 접두사를 제거하거나 배열에서 공백을 지원하는 데 관심이 없으면 따옴표를 삭제하고 루프를 잊어버릴 수 있습니다.
배열을 정리하는 몇 가지 다른 방법은 아래 예제를 참조하십시오.
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
산출량
Choose an option:
1) foobar
2) foo bar
3) s
4) Quit
Option?
도움이 되길 바랍니다.
두 번째 요소를 삭제하려는 경우와 같은 구문도 있습니다.
array=("${array[@]:0:1}" "${array[@]:2}")
두 개의 탭이 연결되어 있습니다.첫 번째는 인덱스 0에서 인덱스 1(전용)까지, 두 번째는 인덱스 2에서 끝까지입니다.
POSIX 셸 스크립트에 배열이 없습니다.
그래서 아마도 당신은 다음과 같은 특정한 방언을 사용하고 있을 것입니다.bash
또는 콘개또는조▁or.zsh
.
따라서 현재 당신의 질문에 답변할 수 없습니다.
이 방법이 도움이 될 수도 있습니다.
unset array[$delete]
제가 하는 일은:
array="$(echo $array | tr ' ' '\n' | sed "/itemtodelete/d")"
BAM, 해당 항목이 제거되었습니다.
이는 간단한 경우에는 작동하지만 (a) 정규식 특수 문자가 있는 경우에는 작동하지 않는 빠르고 더러운 솔루션입니다.$delete
또는 (b) 모든 항목에 공백이 있습니다.시작:
array+=(pluto)
array+=(pippo)
delete=(pluto)
하게 일치하는 모든 $delete
:
array=(`echo $array | fmt -1 | grep -v "^${delete}$" | fmt -999999`)
으로 결적으로과.echo $array
하기: -> 피포, 배열지확니다인합인다▁-확.echo $array[1]
-> 삐뽀
fmt
애매해요: 약간모니다합호다.fmt -1
첫 번째 열에서 랩합니다(각 항목을 고유한 줄에 배치).여기서 공간에 있는 항목에 문제가 발생합니다.) fmt -999999
한 줄로 다시 포장을 풀고 항목 사이의 공백을 뒤로 놓습니다.이를 위한 다른 방법은 다음과 같습니다.xargs
.
부록:첫 번째 일치 항목만 삭제하려면 다음 설명에 따라 sed를 사용합니다.
array=(`echo $array | fmt -1 | sed "0,/^${delete}$/{//d;}" | fmt -999999`)
사실 방금 전에 셸 구문에는 질문에서 제안한 것처럼 항목을 제거해야 할 때 배열을 쉽게 재구성할 수 있는 동작이 내장되어 있다는 것을 알게 되었습니다.
# 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+=()
구문?
한 번에 두 개 이상의 항목을 추가할 수 있습니다. 즉, 전체 배열의 내용을 추가할 수 있습니다.
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
어레이 인덱스와의 충돌을 방지하려면 다음을 사용합니다.unset
자세한 내용은 https://stackoverflow.com/a/49626928/3223785 및 https://stackoverflow.com/a/47798640/3223785 을 참조하십시오. 어레이를 자체적으로 재할당합니다.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
[참조: https://tecadmin.net/working-with-array-bash-script/ ]
다음과 같은 것은 어떻습니까?
array=(one two three)
array_t=" ${array[@]} "
delete=one
array=(${array_t// $delete / })
unset array_t
#/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
언급URL : https://stackoverflow.com/questions/16860877/remove-an-element-from-a-bash-array
'it-source' 카테고리의 다른 글
Bash 백스틱과 동일한 배치 (0) | 2023.05.01 |
---|---|
무엇을 탐지할 수 있습니까?NET Framework 버전 및 서비스 팩이 설치되어 있습니까? (0) | 2023.05.01 |
Mongodb v4.0 트랜잭션, MongoError:트랜잭션 번호는 복제본 집합 구성원 또는 몽고에서만 허용됩니다. (0) | 2023.04.26 |
C#의 여러 줄 문자열 리터럴 (0) | 2023.04.26 |
Git에 푸시 중 오류 코드 403을 반환합니다. HTTP 요청 실패 (0) | 2023.04.26 |