programing

Bash의 어레이에서 고유한 값을 가져오려면 어떻게 해야 합니까?

newstyles 2023. 5. 24. 21:45

Bash의 어레이에서 고유한 값을 가져오려면 어떻게 해야 합니까?

저는 여기와 거의 같은 질문을 받았습니다.

나는 다음을 포함하는 배열을 가지고 있습니다.aa ab aa ac aa ad 이 를 모두 . 이제 이 배열에서 고유한 요소를 모두 선택하려고 합니다.생각해보면, 이것은 간단할 것입니다.sort | uniq또는 와 함께sort -u그들이 다른 질문에서 언급한 것처럼, 그러나 배열에서 아무것도 변하지 않았습니다...코드는 다음과 같습니다.

echo `echo "${ids[@]}" | sort | uniq`

내가 뭘 잘못하고 있는 거지?

약간 진부하지만, 이것은 그것을 할 수 있을 것입니다.

echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '

정렬된 고유 결과를 다시 배열에 저장하려면 배열 할당을 수행합니다.

sorted_unique_ids=($(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' '))

셸이 문자열을 지원하는 경우(bash그래야 함), 당신은 절약할 수 있습니다.echo다음으로 변경하여 처리:

tr ' ' '\n' <<< "${ids[@]}" | sort -u | tr '\n' ' '

2021년 8월 28일 기준 노트:

ShellCheck wiki 2207a에 따르면read -a파이프가 갈라지지 않도록 사용해야 합니다.따라서 bash에서 명령은 다음과 같습니다.

IFS=" " read -r -a ids <<< "$(echo "${ids[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')"

또는

IFS=" " read -r -a ids <<< "$(tr ' ' '\n' <<< "${ids[@]}" | sort -u | tr '\n' ' ')"

입력:

ids=(aa ab aa ac aa ad)

출력:

aa ab ac ad

설명:

  • "${ids[@]}"배열 으로, 셸일작위구한문여을(사지는부되용로업배열부일여)의 echo또는 여기 끈.@" part는 " 레의를모요소든어다의"를합니다.
  • tr ' ' '\n'모든 공백을 새 줄로 변환합니다.배열이 셸에 의해 공백으로 구분된 단일 줄의 요소로 표시되고 정렬에서는 입력이 별도의 줄에 있을 것으로 예상되기 때문입니다.
  • sort -u 요소만 합니다.
  • tr '\n' ' '앞에서 추가한 새 줄을 다시 공백으로 변환합니다.
  • $(...)명령 대체
  • 별도: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는 두 인 루가두번값도니다합에 합니다.aaa[2]를 .b[aa]원래는 을 위해 설정된.a[0].

수 .sort그리고.uniq그러나 더 큰 데이터 세트의 경우 awk, python 등과 같은 더 강력한 언어를 사용하면 더 나은 성능을 볼 수 있습니다.

만약 당신이 자신감을 느낀다면, 당신은 피할 수 있습니다.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, 이 없다고 100%하지 못한다면 대신 for 셰프너, 글렌 잭맨, 그레이캣이 코드에 문제를 발견하지 못할 것이라고 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
~>

셸문자가 수 ?) 를 들어, 배요공다그나셸백있경문특른는자가우있수수까니습이확먼표합다저해니현야큰옴표로따배캡을열처면할려하않신열렇고지소에다)▁if▁in그▁e▁have▁your▁elements▁or!▁(▁special▁quotes▁do표▁space합 저먼▁white▁character)▁array큰다캡니해야현▁array배따옴▁your▁double▁those▁any표로▁express을배▁capture▁just▁this▁toand열 예를 들어,"${a[@]}"Bash는 이를 문자 그대로 "별도의 각 배열 요소"로 해석합니다.bash 내에서 이것은 항상, 항상 작동합니다.

그런 다음 정렬된(그리고 고유한) 배열을 얻으려면 정렬 이해 형식으로 변환하고 bash 배열 요소로 다시 변환할 수 있어야 합니다.이것이 제가 생각한 최고입니다.

eval a=($(printf "%q\n" "${a[@]}" | sort -u))

안타깝게도 빈 배열의 특수한 경우에는 이 작업이 실패하여 빈 배열이 1개의 빈 요소 배열로 바뀝니다(printf에는 0개의 인수가 있지만 여전히 하나의 빈 인수가 있는 것처럼 인쇄되기 때문입니다. 설명 참조).그래서 당신은 그것을 if 같은 것에서 잡아야 합니다.

설명:printf "shell"에 대한 %q 형식은 bash가 eval과 같은 방식으로 복구될 수 있는 방식으로 인쇄된 인수를 이스케이프합니다.각 요소는 자체 라인에서 이스케이프된 인쇄 셸이므로 요소 사이의 유일한 구분 기호는 새 라인이며 배열 할당은 각 라인을 요소로 사용하여 이스케이프된 값을 리터럴 텍스트로 구문 분석합니다.

예.

> a=("foo bar" baz)
> printf "%q\n" "${a[@]}"
'foo bar'
baz
> printf "%q\n"
''

평가는 배열로 돌아가는 각 값에서 탈출을 제거하는 데 필요합니다.

'for-loop'을 사용하여 for-loop의 출력 순서를 지정할 수 있습니다.

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) )그것은 공간에서 부서질 것입니다.

원래 주문을 손실하지 않고 다음을 수행합니다.

uniques=($(tr ' ' '\n' <<<"${original[@]}" | awk '!u[$0]++' | tr '\n' ' '))

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

고양이 번호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

레코드 바꾸기: 중복레교체:cat number.txt | awk '{for(i=1;i<=NF;i++) print $i}' |awk '!x[$0]++'

1
2
3
4
5
6

레코드만 : 유니크만찾기:cat number.txt | awk '{for(i=1;i<=NF;i++) print $i|"sort|uniq -u"}

1
5
6

이 변형은 어떻습니까?

printf '%s\n' "${ids[@]}" | sort -u

공백을 하는 또 을 사용하여 null-delimit을 입니다.printf와별되로 sort그런 다음 루프를 사용하여 다시 배열로 패킹합니다.

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)

이 일이 끝나면,input그리고.output원하는 값 포함(순서가 중요하지 않은 경우):

$ printf "%q\n" "${input[@]}"
a
b
c
$'d\ne'
b
c
$'d\ne'

$ printf "%q\n" "${output[@]}"
a
b
c
$'d\ne'

에서 다음의 .bash그리고.sh 는 가 없는 리고오없다 니습가류그.shellcheck하지만 SC2207을 억제해야 합니다.

arrOrig=("192.168.3.4" "192.168.3.4" "192.168.3.3")

# NO SORTING
# shellcheck disable=SC2207
arr1=($(tr ' ' '\n' <<<"${arrOrig[@]}" | awk '!u[$0]++' | tr '\n' ' ')) # @estani
len1=${#arr1[@]}
echo "${len1}"
echo "${arr1[*]}"

# SORTING
# shellcheck disable=SC2207
arr2=($(printf '%s\n' "${arrOrig[@]}" | sort -u)) # @das.cyklone
len2=${#arr2[@]}
echo "${len2}"
echo "${arr2[*]}"

# SORTING
# shellcheck disable=SC2207
arr3=($(echo "${arrOrig[@]}" | tr ' ' '\n' | sort -u | tr '\n' ' ')) # @sampson-chen
len3=${#arr3[@]}
echo "${len3}"
echo "${arr3[*]}"

# SORTING
# shellcheck disable=SC2207
arr4=($(for i in "${arrOrig[@]}"; do echo "${i}"; done | sort -u)) # @corbyn42
len4=${#arr4[@]}
echo "${len4}"
echo "${arr4[*]}"

# NO SORTING
# shellcheck disable=SC2207
arr5=($(echo "${arrOrig[@]}" | tr "[:space:]" '\n' | awk '!a[$0]++')) # @faustus
len5=${#arr5[@]}
echo "${len5}"
echo "${arr5[*]}"

# OUTPUTS

# arr1
2 # length
192.168.3.4 192.168.3.3 # items

# arr2
2 # length
192.168.3.3 192.168.3.4 # items

# arr3
2 # length
192.168.3.3 192.168.3.4 # items

# arr4
2 # length
192.168.3.3 192.168.3.4 # items

# arr5
2 # length
192.168.3.4 192.168.3.3 # items

이 모든 출력은 2이며 정확합니다.이 답변은 기본적으로 이 게시물의 다른 답변을 요약하고 정리하며 유용한 빠른 참조입니다.원래 답변에 대한 귀인이 제공됩니다.

zsh에서 (u) 플래그를 사용할 수 있습니다.

$ ids=(aa ab aa ac aa ad)
$ print ${(u)ids}
aa ab ac ad

파일의 첫 번째 열에 대한 고유 값을 가져오려면 이 작업을 수행합니다.

awk -F, '{a[$1];}END{for (i in a)print i;}'
# 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