Bash의 배열에서 고유 한 값을 얻으려면 어떻게해야합니까?
aa ab aa ac aa ad
등 을 포함하는 배열이 있습니다 . 이제이 배열에서 모든 고유 한 요소를 선택하고 싶습니다. 생각은,이 간단한 것 sort | uniq
또는과 sort -u
배열에 변화가 다른 문제에 언급, 아무것도하지만 ... 코드는 다음과 같습니다
echo `echo "${ids[@]}" | sort | uniq`
내가 도대체 뭘 잘못하고있는 겁니까?
약간 해키하지만 다음과 같이해야합니다.
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
.
자신감이 있다면 여러 인수에 대해 형식을 재활용하는의 기능을 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) )
. 공백에서 깨집니다.
bash 내부 만 사용하는 솔루션을 원하는 경우 값을 연관 배열의 키로 설정 한 다음 키를 추출 할 수 있습니다.
declare -A uniqs
list=(foo bar bar "bar none")
for f in "${list[@]}"; do
uniqs["${f}"]=""
done
for thing in "${!uniqs[@]}"; do
echo "${thing}"
done
이것은 출력됩니다
bar
foo
bar none
고양이 number.txt
1 2 3 4 4 3 2 5 6
열에 줄 인쇄 :
cat number.txt | awk '{for(i=1;i<=NF;i++) print $i}'
1
2
3
4
4
3
2
5
6
중복 기록 찾기 :
cat number.txt | awk '{for(i=1;i<=NF;i++) print $i}' |awk 'x[$0]++'
4
3
2
Replace duplicate records:
cat number.txt | awk '{for(i=1;i<=NF;i++) print $i}' |awk '!x[$0]++'
1
2
3
4
5
6
Find only Uniq records:
cat number.txt | awk '{for(i=1;i<=NF;i++) print $i|"sort|uniq -u"}
1
5
6
Without loosing the original ordering:
uniques=($(tr ' ' '\n' <<<"${original[@]}" | awk '!u[$0]++' | tr '\n' ' '))
Try this to get uniq values for first column in file
awk -F, '{a[$1];}END{for (i in a)print i;}'
Another option for dealing with embedded whitespace, is to null-delimit with printf
, make distinct with sort
, then use a loop to pack it back into an array:
input=(a b c "$(printf "d\ne")" b c "$(printf "d\ne")")
output=()
while read -rd $'' element
do
output+=("$element")
done < <(printf "%s\0" "${input[@]}" | sort -uz)
At the end of this, input
and output
contain the desired values (provided order isn't important):
$ printf "%q\n" "${input[@]}"
a
b
c
$'d\ne'
b
c
$'d\ne'
$ printf "%q\n" "${output[@]}"
a
b
c
$'d\ne'
# Read a file into variable
lines=$(cat /path/to/my/file)
# Go through each line the file put in the variable, and assign it a variable called $line
for line in $lines; do
# Print the line
echo $line
# End the loop, then sort it (add -u to have unique lines)
done | sort -u
참고URL : https://stackoverflow.com/questions/13648410/how-can-i-get-unique-values-from-an-array-in-bash
'Development Tip' 카테고리의 다른 글
"/", "\"를 사용한 플랫폼 독립적 경로 연결? (0) | 2020.10.31 |
---|---|
oh-my-zsh는 느리지 만 특정 Git 저장소에서만 (0) | 2020.10.31 |
Git Bash 터미널에서 Bitbucket에 새 저장소를 만드시겠습니까? (0) | 2020.10.31 |
bash에서 파일의 절대 디렉토리를 어떻게 얻습니까? (0) | 2020.10.31 |
PowerShell 복사 스크립트에서 여러 문자열을 올바르게 필터링하는 방법 (0) | 2020.10.31 |