답변
약간 해키하지만 이렇게해야합니다.
echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '
정렬 된 고유 결과를 다시 배열에 저장하려면 Array 할당을 수행하십시오 .
sorted_unique_ids=($(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))
쉘이 herestrings ( bash
should)를 지원하는 경우 다음과 같이 echo
변경 하여 프로세스를 절약 할 수 있습니다 .
tr ' ' '\n' <<< "${ids[@]}" | sort -u | tr '\n' ' '
입력:
ids=(aa ab aa ac aa ad)
산출:
aa ab ac ad
설명:
"${ids[@]}"
-쉘 배열로 작업하기위한 구문echo
.@
부분 수단 “어레이의 모든 요소 「tr ' ' '\n'
-모든 공백을 개행으로 변환합니다. 배열은 쉘에서 공백으로 구분 된 한 줄의 요소로 표시되기 때문입니다. 그리고 sort는 입력이 별도의 줄에있을 것으로 예상하기 때문입니다.sort -u
-고유 한 요소 만 정렬 및 유지tr '\n' ' '
-앞에서 추가 한 줄 바꿈을 다시 공백으로 변환합니다.$(...)
– 명령 대체- Aside :
tr ' ' '\n' <<< "${ids[@]}"
는보다 효율적인 방법입니다.echo "${ids[@]}" | tr ' ' '\n'
답변
Bash 버전 4 이상 (최신 Linux 버전의 경우)을 실행하는 경우 원래 배열의 각 값을 포함하는 새로운 연관 배열을 만들어 bash에서 고유 한 배열 값을 가져올 수 있습니다. 이 같은:
$ a=(aa ac aa ad "ac ad")
$ declare -A b
$ for i in "${a[@]}"; do b["$i"]=1; done
$ printf '%s\n' "${!b[@]}"
ac ad
ac
aa
ad
이는 모든 배열 (모든 언어의 연관 또는 전통)에서 각 키가 한 번만 나타날 수 있기 때문에 작동합니다. 때 for
루프의 두 번째 값에 도달 aa
에 a[2]
덮어 쓰고 b[aa]
위해 원래 설정 하였다 a[0]
.
기본 bash는 일을하는 것은 파이프와 같은 외부 도구를 사용하는 것보다 빠를 수 있습니다 sort
그리고 uniq
당신은 등 AWK, 파이썬, 같은 더 강력한 언어를 사용하는 경우 더 큰 데이터 세트에 대한 당신이 가능성이 더 나은 성능을 볼 수 있지만,
자신감이 있다면 여러 인수에 대해 형식을 재활용하는의 기능을 for
사용하여 루프를 피할 수 있습니다 . (괜찮 으면 지금 읽기를 중단하십시오.)printf
eval
$ eval b=( $(printf ' ["%s"]=1' "${a[@]}") )
$ declare -p b
declare -A b=(["ac ad"]="1" [ac]="1" [aa]="1" [ad]="1" )
이 솔루션에 필요한 이유 eval
는 단어 분할 전에 배열 값이 결정되기 때문입니다. 즉, 명령 대체의 출력 은 키 = 값 쌍 세트가 아니라 단일 단어 로 간주됩니다 .
이것은 서브 쉘을 사용하지만 배열 값을 처리하기 위해 bash 내장 기능 만 사용합니다. eval
비판적인 눈으로 사용을 평가하십시오 . chepner 또는 glenn jackman 또는 greycat이 코드에서 오류를 찾지 못할 것이라고 100 % 확신하지 못하는 경우 대신 for 루프를 사용하십시오.
답변
이미 답변을 받았지만 검색 결과에서 상당히 높게 나타 났으며 누군가에게 도움이 될 수 있습니다.
printf "%s\n" "${IDS[@]}" | sort -u
예:
~> IDS=( "aa" "ab" "aa" "ac" "aa" "ad" )
~> echo "${IDS[@]}"
aa ab aa ac aa ad
~>
~> printf "%s\n" "${IDS[@]}" | sort -u
aa
ab
ac
ad
~> UNIQ_IDS=($(printf "%s\n" "${IDS[@]}" | sort -u))
~> echo "${UNIQ_IDS[@]}"
aa ab ac ad
~>
답변
배열 요소에 공백이나 다른 쉘 특수 문자가있는 경우 (그렇지 않은지 확신 할 수 있습니까?) 먼저이를 캡처하려면 (항상 이렇게해야 함) 배열을 큰 따옴표로 표현하십시오! 예 : "${a[@]}"
. Bash는 문자 그대로 이것을 “개별 인수의 각 배열 요소”로 해석합니다 . bash 내에서 이것은 항상 항상 작동합니다.
그런 다음 정렬 된 (및 고유 한) 배열을 얻으려면 정렬이 이해하는 형식으로 변환하고이를 bash 배열 요소로 다시 변환 할 수 있어야합니다. 이것이 내가 생각 해낸 최고입니다.
eval a=($(printf "%q\n" "${a[@]}" | sort -u))
불행히도 이것은 빈 배열의 특별한 경우에 실패하여 빈 배열을 1 개의 빈 요소의 배열로 바꿉니다 (printf에 0 개의 인수가 있지만 여전히 하나의 빈 인수가있는 것처럼 인쇄하기 때문에-설명 참조). 그래서 당신은 if 또는 something에서 그것을 잡아야합니다.
설명 : printf의 % q 형식은 bash가 eval과 같이 복구 할 수있는 것과 같은 방식으로 인쇄 된 인수를 “이스케이프”합니다. 각 요소는 자체 줄에서 이스케이프 처리 된 셸로 인쇄되기 때문에 요소 사이의 유일한 구분 기호는 개행이며 배열 할당은 각 줄을 요소로 사용하여 이스케이프 된 값을 리터럴 텍스트로 구문 분석합니다.
예 :
> a=("foo bar" baz)
> printf "%q\n" "${a[@]}"
'foo bar'
baz
> printf "%q\n"
''
eval은 어레이로 돌아가는 각 값에서 이스케이프를 제거하는 데 필요합니다.
답변
‘sort’는 for 루프의 출력을 정렬하는 데 사용할 수 있습니다.
for i in ${ids[@]}; do echo $i; done | sort
“-u”로 중복 제거 :
for i in ${ids[@]}; do echo $i; done | sort -u
마지막으로 고유 한 요소로 배열을 덮어 쓸 수 있습니다.
ids=( `for i in ${ids[@]}; do echo $i; done | sort -u` )
답변
이것은 또한 순서를 유지합니다.
echo ${ARRAY[@]} | tr [:space:] '\n' | awk '!a[$0]++'
고유 값으로 원래 배열을 수정하려면 다음을 수행하십시오.
ARRAY=($(echo ${ARRAY[@]} | tr [:space:] '\n' | awk '!a[$0]++'))
답변
고유 한 값으로 구성된 새 배열을 만들려면 배열이 비어 있지 않은지 확인한 후 다음 중 하나를 수행하십시오.
중복 항목 제거 (정렬 사용)
readarray -t NewArray < <(printf '%s\n' "${OriginalArray[@]}" | sort -u)
중복 항목 제거 (정렬하지 않음)
readarray -t NewArray < <(printf '%s\n' "${OriginalArray[@]}" | awk '!x[$0]++')
경고 : NewArray=( $(printf '%s\n' "${OriginalArray[@]}" | sort -u) )
. 공백에서 깨집니다.