Bash에서 어레이를 정렬하는 방법
Bash에 다음과 같은 어레이가 있습니다.
array=(a c b f 3 5)
어레이를 분류해야 합니다.콘텐츠를 정렬된 방식으로 표시할 뿐만 아니라 정렬된 요소를 사용하여 새 배열을 가져옵니다.정렬된 새 배열은 완전히 새 배열이거나 이전 배열일 수 있습니다.
그렇게 많은 코드가 필요하지 않습니다.
IFS=$'\n' sorted=($(sort <<<"${array[*]}"))
unset IFS
요소의 공백(뉴라인이 아닌 한)을 지원하며 Bash 3.x에서 작동합니다.
예:
$ array=("a c" b f "3 5")
$ IFS=$'\n' sorted=($(sort <<<"${array[*]}")); unset IFS
$ printf "[%s]\n" "${sorted[@]}"
[3 5]
[a c]
[b]
[f]
주의: @sorontar는 요소에 다음과 같은 와일드카드가 포함되어 있는 경우 주의가 필요하다고 지적했습니다.* ★★★★★★★★★★★★★★★★★」?:
sorted = ( ... ) glob".: 지구본을 꺼야 .
set -f★★★★★★★★★★★★★★★★★」set -o noglob★★★★★★★★★★★★★★★★★」shopt -op noglob(예: 는어 of of of)*파일 목록으로 확장됩니다.
현상:
그 결과, 다음과 같은 순서로 6가지 작업이 완료됩니다.
IFS=$'\n'"${array[*]}"<<<sortsorted=($(...))unset IFS
, ★★★★★★★★★★★★★★.IFS=$'\n'
이는 2와 5의 결과에 다음과 같은 방식으로 영향을 미치는 운영의 중요한 부분입니다.
지정:
"${array[*]}"는 첫 문자로 된 모든 됩니다.IFSsorted=()모든 문자를 분할하여 요소를 만듭니다.IFS
IFS=$'\n' 요소가 새 줄을 구분 기호로 사용하여 확장되고 나중에 각 줄이 요소가 되는 방식으로 작성되도록 설정합니다(예: 새 줄로 분할).
합니다. 줄 바꿈이 합니다.그렇게 해야 하기 때문입니다.sort동작합니다(회선당 1개씩).새 선으로만 분할하는 것은 중요하지 않지만 공백 또는 탭이 포함된 요소를 보존해야 합니다.
" " "IFS공간, 탭, 그 뒤에 새로운 행이 이어지는 경우 작업에 적합하지 않습니다.
다음, 음음 next next next next next?sort <<<"${array[*]}" 교환
<<<여기서 스트링이라고 하는 것은, 다음의 확장 방법을 취합니다."${array[*]}"와 같이 sort.
예에서는, 「」를 해 주세요.sort에는 다음 문자열이 입력됩니다.
a c
b
f
3 5
★★sort sort, 생성:
3 5
a c
b
f
다음, 음음 next next next next next?sorted=($(...)) 교환
$(...)명령어 치환이라고 불리는 파트가 그 내용을 발생시킵니다(sort <<<"${array[*]}일반 명령어로 실행되며 결과 표준 출력을 리터럴로 사용합니다.$(...)
이 예에서는 다음과 같이 간단하게 기술할 수 있습니다.
sorted=(3 5
a c
b
f
)
sorted이 리터럴을 새로운 행으로 분할하여 작성된 배열이 됩니다.
★★★★★★★★★★★★★★★★★★★.unset IFS
.IFS디폴트값으로 설정합니다.이치노
이는 우리가 위해서입니다.IFS(그렇지 않으면 복잡한 스크립트에 적합하지 않을 수 있는 상황을 전환했다는 것을 기억해야 합니다.)
원래 응답:
array=(a c b "f f" 3 5)
readarray -t sorted < <(for a in "${array[@]}"; do echo "$a"; done | sort)
출력:
$ for a in "${sorted[@]}"; do echo "$a"; done
3
5
a
b
c
f f
이 버전은 특수 문자 또는 공백(뉴라인 제외)을 포함하는 값을 처리합니다.
메모 readarray는 bash 4+에서 지원됩니다.
편집 @Dimitre의 제안에 따라 업데이트한 내용:
readarray -t sorted < <(printf '%s\0' "${array[@]}" | sort -z | xargs -0n1)
줄바꿈 문자가 올바르게 삽입된 정렬 요소를 이해할 수 있는 이점도 있습니다.불행히도 @ruakh에서 올바르게 표시되었듯이 이는 다음 결과를 의미하지 않습니다.readarray맞겠죠. 왜냐하면readarray에는 사용할 수 있는 .NUL일반 줄 바꿈 대신 줄 바꿈을 사용합니다.
배열 요소에서 특수 셸 문자를 처리할 필요가 없는 경우:
array=(a c b f 3 5)
sorted=($(printf '%s\n' "${array[@]}"|sort))
bash를 사용하는 경우 외부 정렬 프로그램이 필요합니다.
zsh를 사용하면 외부 프로그램이 필요하지 않으며 특수 셸 문자를 쉽게 처리할 수 있습니다.
% array=('a a' c b f 3 5); printf '%s\n' "${(o)array[@]}"
3
5
a a
b
c
f
ksh는 가지고 있다set -sASCIIbetic으로 정렬합니다.
다음은 순수 Bash QuickSort 구현입니다.
#!/bin/bash
# quicksorts positional arguments
# return is in array qsort_ret
qsort() {
local pivot i smaller=() larger=()
qsort_ret=()
(($#==0)) && return 0
pivot=$1
shift
for i; do
# This sorts strings lexicographically.
if [[ $i < $pivot ]]; then
smaller+=( "$i" )
else
larger+=( "$i" )
fi
done
qsort "${smaller[@]}"
smaller=( "${qsort_ret[@]}" )
qsort "${larger[@]}"
larger=( "${qsort_ret[@]}" )
qsort_ret=( "${smaller[@]}" "$pivot" "${larger[@]}" )
}
예를 들어 다음과 같이 사용합니다.
$ array=(a c b f 3 5)
$ qsort "${array[@]}"
$ declare -p qsort_ret
declare -a qsort_ret='([0]="3" [1]="5" [2]="a" [3]="b" [4]="c" [5]="f")'
이 구현은 재귀적입니다.따라서 반복적인 QuickSort를 다음에 제시하겠습니다.
#!/bin/bash
# quicksorts positional arguments
# return is in array qsort_ret
# Note: iterative, NOT recursive! :)
qsort() {
(($#==0)) && return 0
local stack=( 0 $(($#-1)) ) beg end i pivot smaller larger
qsort_ret=("$@")
while ((${#stack[@]})); do
beg=${stack[0]}
end=${stack[1]}
stack=( "${stack[@]:2}" )
smaller=() larger=()
pivot=${qsort_ret[beg]}
for ((i=beg+1;i<=end;++i)); do
if [[ "${qsort_ret[i]}" < "$pivot" ]]; then
smaller+=( "${qsort_ret[i]}" )
else
larger+=( "${qsort_ret[i]}" )
fi
done
qsort_ret=( "${qsort_ret[@]:0:beg}" "${smaller[@]}" "$pivot" "${larger[@]}" "${qsort_ret[@]:end+1}" )
if ((${#smaller[@]}>=2)); then stack+=( "$beg" "$((beg+${#smaller[@]}-1))" ); fi
if ((${#larger[@]}>=2)); then stack+=( "$((end-${#larger[@]}+1))" "$end" ); fi
done
}
두 경우 모두 사용하는 순서를 변경할 수 있습니다.문자열 비교를 사용했지만 산술 비교, wrt 파일 수정 시간 비교 등을 사용하여 적절한 테스트를 수행할 수 있습니다.또한 테스트 함수를 사용하는 첫 번째 인수를 사용할 수도 있습니다.
#!/bin/bash
# quicksorts positional arguments
# return is in array qsort_ret
# Note: iterative, NOT recursive! :)
# First argument is a function name that takes two arguments and compares them
qsort() {
(($#<=1)) && return 0
local compare_fun=$1
shift
local stack=( 0 $(($#-1)) ) beg end i pivot smaller larger
qsort_ret=("$@")
while ((${#stack[@]})); do
beg=${stack[0]}
end=${stack[1]}
stack=( "${stack[@]:2}" )
smaller=() larger=()
pivot=${qsort_ret[beg]}
for ((i=beg+1;i<=end;++i)); do
if "$compare_fun" "${qsort_ret[i]}" "$pivot"; then
smaller+=( "${qsort_ret[i]}" )
else
larger+=( "${qsort_ret[i]}" )
fi
done
qsort_ret=( "${qsort_ret[@]:0:beg}" "${smaller[@]}" "$pivot" "${larger[@]}" "${qsort_ret[@]:end+1}" )
if ((${#smaller[@]}>=2)); then stack+=( "$beg" "$((beg+${#smaller[@]}-1))" ); fi
if ((${#larger[@]}>=2)); then stack+=( "$((end-${#larger[@]}+1))" "$end" ); fi
done
}
그런 다음 다음과 같은 비교 기능을 사용할 수 있습니다.
compare_mtime() { [[ $1 -nt $2 ]]; }
및 용도:
$ qsort compare_mtime *
$ declare -p qsort_ret
현재 폴더의 파일을 수정 시간별로 정렬합니다(먼저 삭제).
참고. 이 함수는 순수하게 Bash입니다. 외부 유틸리티도 서브셸도 없습니다.스페이스, 줄바꿈 문자, 글로벌 문자 등 재미있는 기호도 사용할 수 없습니다.
2. 2. 시험[[ $i < $pivot ]] 정답입니다.사전 문자열 비교를 사용합니다.배열에 정수만 포함되어 있고 숫자로 정렬하려면((i < pivot))대신.Please don't edit this answer to change that. It has already been edited (and rolled back) a couple of times. The test I gave here is correct and corresponds to the output given in the example: the example uses both strings and numbers, and the purpose is to sort it in lexicographical order. Using ((i < pivot)) in this case is wrong.
tl;dr:
배열 " " "a_in를 a_out(메모리에 새로운[1] 행이 포함되어 있지 않아야 합니다).
Bash v4+:
readarray -t a_out < <(printf '%s\n' "${a_in[@]}" | sort)
Bash v3:
IFS=$'\n' read -d '' -r -a a_out < <(printf '%s\n' "${a_in[@]}" | sort)
Antak 솔루션과 비교한 장점:
하는 경우 때문에 하기 추가 하지 않습니다.
set -f, , , , 입니다.set +f('아저씨')리셋할
IFSunset IFS를 클릭합니다.[2]
옵션 판독치: 설명 및 샘플 코드
위의 예에서는 Bash 코드를 외부 유틸리티와 조합하여 임의의 단일 행 요소 및 (옵션으로 필드별) 어휘적 또는 숫자적 정렬을 사용하는 솔루션을 제공합니다.
퍼포먼스:약 20개 이상의 요소에 대해 이는 순수 Bash 솔루션보다 빠릅니다. 100개 정도의 요소를 넘어서면 점점 더 빨라집니다.
(정확한 임계값은 특정 입력, 머신 및 플랫폼에 따라 달라집니다).- 빠른 이유는 Bash 루프를 회피하기 때문입니다.
printf '%s\n' "${a_in[@]}" | sort는 정렬을 수행합니다(기본적으로는 의 POSIX 사양을 참조)."${a_in[@]}"a_in(공백 포함)이 무엇이든 개별 인수로 지정합니다.printf '%s\n'그러면 각 인수(즉, 각 배열 요소)가 그대로 각 행에 인쇄됩니다.
프로세스 대체()
<(...)를 사용하여 정렬된 출력을 입력으로 제공합니다.readreadarray, (stdin 로이이이이이이이이이이이이이)<출력 변수에 대해 /를 실행하려면 현재 셸에서 실행되어야 합니다(서브셸에서 실행해서는 안 됩니다).a_out현재 셸에 표시되도록 합니다(스크립트의 나머지 부분에서 정의된 변수를 유지하도록 함).★★★★★
sort의 출력을 배열 변수로 변환합니다.Bash v4+:
readarray -t a_outreads reads reads reads reads reads by by by by by by by by by by by by by by by로 출력되는 각 .sortvariable의 로 합니다.a_out하지 않고요.\n각 요소)에서-t를 참조해 주세요.Bash v3:
readarray하지 않기 때문에, 「 」는 「 」입니다.read사용해야 합니다.
IFS=$'\n' read -d '' -r -a a_outread읽다-a변수a_out입력 ().-d ''줄 바꿈으로써 ).IFS=$'\n'$'\n'리터럴 뉴라인(LF)을 생성하는 것은 이른바 ANSI C 따옴표로 둘러싸인 문자열입니다.
)-r는, 와 함께 가 있는 「」 「」 「」).read「치 않은 」를 합니다.\□□□□□□□□★
주석이 달린 샘플 코드:
#!/usr/bin/env bash
# Define input array `a_in`:
# Note the element with embedded whitespace ('a c')and the element that looks like
# a glob ('*'), chosen to demonstrate that elements with line-internal whitespace
# and glob-like contents are correctly preserved.
a_in=( 'a c' b f 5 '*' 10 )
# Sort and store output in array `a_out`
# Saving back into `a_in` is also an option.
IFS=$'\n' read -d '' -r -a a_out < <(printf '%s\n' "${a_in[@]}" | sort)
# Bash 4.x: use the simpler `readarray -t`:
# readarray -t a_out < <(printf '%s\n' "${a_in[@]}" | sort)
# Print sorted output array, line by line:
printf '%s\n' "${a_out[@]}"
★★★★★★★★★의 사용으로 인해sort옵션이 없는 경우, 다음과 같이 사전 정렬이 이루어집니다(문자 앞에 정렬이 표시되며, 숫자 시퀀스는 숫자가 아닌 사전으로 처리됩니다).
*
10
5
a c
b
f
첫 번째 필드를 기준으로 숫자를 정렬하려면sort -k1,1n한 것이 sort(숫자 앞에 정렬되지 않은 소트 및 숫자가 올바르게 정렬됨)를 출력합니다.
*
a c
b
f
5
10
[1] 줄바꿈이 내장된 요소를 처리하려면 다음 변종(Bash v4+, GNU 포함)을 사용합니다. sort
readarray -d '' -t a_out < <(printf '%s\0' "${a_in[@]}" | sort -z).
Michau Görny의 도움이 되는 답변은 Bash v3 솔루션입니다.
[2] 동안IFS 는 Bash v3 배리언트로 설정되어 있으며 변경 범위는 명령어로 지정됩니다.
뒤에 오는 것은 '아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 아, 네.IFS=$'\n' Antak의 답변은 명령이라기보다 과제이다, 이 경우IFS변화는 글로벌합니다.
뮌헨에서 프랑크푸르트로 가는 3시간 기차여행(옥토버페스트가 내일 시작돼 연락이 닿지 않았다)에서 나는 첫 번째 포스트를 생각하고 있었다.일반적인 정렬 기능에는 글로벌 어레이를 사용하는 것이 훨씬 더 좋습니다.다음 함수는 임의 문자열(새 줄, 공백 등)을 처리합니다.
declare BSORT=()
function bubble_sort()
{ #
# @param [ARGUMENTS]...
#
# Sort all positional arguments and store them in global array BSORT.
# Without arguments sort this array. Return the number of iterations made.
#
# Bubble sorting lets the heaviest element sink to the bottom.
#
(($# > 0)) && BSORT=("$@")
local j=0 ubound=$((${#BSORT[*]} - 1))
while ((ubound > 0))
do
local i=0
while ((i < ubound))
do
if [ "${BSORT[$i]}" \> "${BSORT[$((i + 1))]}" ]
then
local t="${BSORT[$i]}"
BSORT[$i]="${BSORT[$((i + 1))]}"
BSORT[$((i + 1))]="$t"
fi
((++i))
done
((++j))
((--ubound))
done
echo $j
}
bubble_sort a c b 'z y' 3 5
echo ${BSORT[@]}
다음의 출력이 있습니다.
3 5 a b c z y
에서 같은 출력이 생성됩니다.
BSORT=(a c b 'z y' 3 5)
bubble_sort
echo ${BSORT[@]}
아마도 Bash는 내부적으로 스마트 포인터를 사용하고 있기 때문에 스왑 조작은 저렴할 수 있습니다(의심스럽지만).하지만,bubble_sort보다 고도의 기능이merge_sort을 사용하다
솔루션을 하는 또 sort및 특수 문자(NUL : 제외)에 대응합니다.bash-3.2 및 GNU 또는 BSD에서 동작합니다.sort(POSIX)가 되어 있지 않습니다-z를 참조해 주세요.
local e new_array=()
while IFS= read -r -d '' e; do
new_array+=( "${e}" )
done < <(printf "%s\0" "${array[@]}" | LC_ALL=C sort -z)
먼저 마지막에 입력 리다이렉션을 살펴봅니다.쓰죠.printf어레이 요소를 쓰기 위한 기본 제공, 0 종단 처리.을 통해 요소가 되고 셸의 인 내용은 전달됩니다.printf나머지 각 파라미터에 대해 형식 문자열의 마지막 부분을 재사용합니다. '다, 하다, 하다와 입니다.
for e in "${array[@]}"; do
printf "%s\0" "${e}"
done
는 "Da's Knull-terminated 요소 리스트는 ada로 전달됩니다.sort . 。-z옵션을 지정하면 Null 종단 요소를 읽고 정렬하여 Null 종단 요소를 출력합니다.할 수 .-u이 좋기 uniq -z . 。LC_ALL=C로케일에 안정된 합니다.scriptss, scripts.s, scripts.s, scripts.s, scripts, scripts, scripts, scripts.s, scripts, scripts.스크립트에 도움이 되는 경우도 있습니다.「 」를 sort로케일을 존중하려면 해당 로케일을 삭제해 주세요.
<()파이프라인에서 를 가져오고 constructure는 descriptor를 .<는, 을 리다이렉트 합니다.while루프로 접속합니다.파이프 내부의 표준 입력에 액세스 할 필요가 있는 경우는, 다른 디스크립터(reader의 연습:)를 사용할 수 있습니다.
.readstdin stdin dindin din din din 、 din din 、 din din din din 、 설정 ★★IFS 분할을 디세블로 그 결과, 「스플릿」이 됩니다.★★★★★★★★★★★★★★★★★★·read는 제공된 단일 변수에 대한 입력의 전체 '줄'을 읽습니다. -r 이스케이프 합니다.option은 바람직하지 않은 이스케이프 처리를 디세블로 합니다. ㅇㅇㅇㅇㅇ.-d ''NUL로 NUL은 "NUL"을 나타냅니다.read 끝 읽습니다.
되는 제로 되며, 이 은 그결,, 회회회회 1회, 음음음음회회 음회 회회회 음회 회회 회회 회회 음회 음회 음회회 음 음 음 음 음 as as as as as as as as in in in in in in in in in in in in in in in in in in in in in in in in in ine이 예에서는 항목을 다른 배열에 넣을 뿐이지만 직접 처리하는 것을 선호할 수 있습니다. : )
물론, 그것은 같은 목표를 달성하기 위한 많은 방법 중 하나일 뿐이다.제가 보기에 이것은 bash에서 완전한 정렬 알고리즘을 구현하는 것보다 간단하고 경우에 따라서는 더 빠릅니다.줄바꿈을 포함한 모든 특수 문자를 처리하며 대부분의 일반 시스템에서 작동합니다.가장 중요한 것은, bash:)에 대해 새롭고 멋진 것을 가르쳐 줄지도 모른다는 점입니다.
심플하게 해 주세요;)
예제에서는 이 "D"로 되어 있습니다.b입니다.a!
줄 " " "echo 의 각 " " "a , , , 「 」pipe에 접속합니다.sort하기 위해 사용됩니다.b.
a=(2 3 1)
b=( $( for x in ${a[@]}; do echo $x; done | sort ) )
echo ${b[@]} # output: 1 2 3
최소 정렬:
#!/bin/bash
array=(.....)
index_of_element1=0
while (( ${index_of_element1} < ${#array[@]} )); do
element_1="${array[${index_of_element1}]}"
index_of_element2=$((index_of_element1 + 1))
index_of_min=${index_of_element1}
min_element="${element_1}"
for element_2 in "${array[@]:$((index_of_element1 + 1))}"; do
min_element="`printf "%s\n%s" "${min_element}" "${element_2}" | sort | head -n+1`"
if [[ "${min_element}" == "${element_2}" ]]; then
index_of_min=${index_of_element2}
fi
let index_of_element2++
done
array[${index_of_element1}]="${min_element}"
array[${index_of_min}]="${element_1}"
let index_of_element1++
done
이것을 시험해 보세요.
echo ${array[@]} | awk 'BEGIN{RS=" ";} {print $1}' | sort
출력은 다음과 같습니다.
35abcf
문제는 해결됐습니다.
어레이의 각 요소에 대해 다음과 같이 하나의 정수를 계산할 수 있는 경우:
tab='0123456789abcdefghijklmnopqrstuvwxyz'
# build the reversed ordinal map
for ((i = 0; i < ${#tab}; i++)); do
declare -g ord_${tab:i:1}=$i
done
function sexy_int() {
local sum=0
local i ch ref
for ((i = 0; i < ${#1}; i++)); do
ch="${1:i:1}"
ref="ord_$ch"
(( sum += ${!ref} ))
done
return $sum
}
sexy_int hello
echo "hello -> $?"
sexy_int world
echo "world -> $?"
그러면 다음 정수를 배열 인덱스로 사용할 수 있습니다. Bash는 항상 스파스 배열을 사용하기 때문에 사용하지 않는 인덱스에 대해 걱정할 필요가 없습니다.
array=(a c b f 3 5)
for el in "${array[@]}"; do
sexy_int "$el"
sorted[$?]="$el"
done
echo "${sorted[@]}"
- 찬성. 빠른.
- 단점: 중복된 요소가 병합되어 콘텐츠를 32비트 고유 정수에 매핑할 수 없습니다.
array=(a c b f 3 5)
new_array=($(echo "${array[@]}" | sed 's/ /\n/g' | sort))
echo ${new_array[@]}
new_array의 에코 내용은 다음과 같습니다.
3 5 a b c f
공간 및 줄 바꿈의 일반적인 문제에 대한 회피책이 있습니다.
배열에 예: " " " " " )를 사용합니다.$'\1' ★★★★★★★★★★★★★★★★★」$'\4'★★★★★★★★★★★★★★★★★★」
이 함수는 작업을 완료합니다.
# Sort an Array may have spaces or newlines with a workaround (wa=$'\4')
sortarray(){ local wa=$'\4' IFS=''
if [[ $* =~ [$wa] ]]; then
echo "$0: error: array contains the workaround char" >&2
exit 1
fi
set -f; local IFS=$'\n' x nl=$'\n'
set -- $(printf '%s\n' "${@//$nl/$wa}" | sort -n)
for x
do sorted+=("${x//$wa/$nl}")
done
}
어레이가 정렬됩니다.
$ array=( a b 'c d' $'e\nf' $'g\1h')
$ sortarray "${array[@]}"
$ printf '<%s>\n' "${sorted[@]}"
<a>
<b>
<c d>
<e
f>
<gh>
이로 인해 소스 어레이에 회피책 문자가 포함되어 있다는 불만이 제기됩니다.
$ array=( a b 'c d' $'e\nf' $'g\4h')
$ sortarray "${array[@]}"
./script: error: array contains the workaround char
묘사
- 두 했습니다.
wa문자)및 늘 (' ' )의 IFS - 다음 (null인 경우) 가 null인 합니다.
$*. - charter는 되어 있지 .
[[ $* =~ [$wa] ]]. - 했을 경우는, 합니다.「 」 。
exit 1 - 이름 . " " " " " " :
set -f - 의 합니다(IFS " " " 。
IFS=$'\n'a variable ) 。xvar신규 라인바)nl=$'\n'를 참조해 주세요. - 배열)의 합니다.
$@를 참조해 주세요. - , 새로운 은 모두 문자, 즉 회피책 문자로 됩니다.
"${@//$nl/$wa}". - 보내다
sort -n. - 인수로 .
set --. - 그런 다음 (새 행을 보존하기 위해) 각 인수를 하나씩 할당합니다.
for x- 로 : " 로 to to to to to to to to 。
sorted+=(…) - 따옴표를 사용하여 기존 줄바꿈을 보존합니다.
- 복원
"${x//$wa/$nl}". - 다 했어요.
이 질문은 밀접한 관련이 있어 보인다.BTW는 Bash의 머지소트(외부 프로세스 없음)입니다.
mergesort() {
local -n -r input_reference="$1"
local -n output_reference="$2"
local -r -i size="${#input_reference[@]}"
local merge previous
local -a -i runs indices
local -i index previous_idx merged_idx \
run_a_idx run_a_stop \
run_b_idx run_b_stop
output_reference=("${input_reference[@]}")
if ((size == 0)); then return; fi
previous="${output_reference[0]}"
runs=(0)
for ((index = 0;;)) do
for ((++index;; ++index)); do
if ((index >= size)); then break 2; fi
if [[ "${output_reference[index]}" < "$previous" ]]; then break; fi
previous="${output_reference[index]}"
done
previous="${output_reference[index]}"
runs+=(index)
done
runs+=(size)
while (("${#runs[@]}" > 2)); do
indices=("${!runs[@]}")
merge=("${output_reference[@]}")
for ((index = 0; index < "${#indices[@]}" - 2; index += 2)); do
merged_idx=runs[indices[index]]
run_a_idx=merged_idx
previous_idx=indices[$((index + 1))]
run_a_stop=runs[previous_idx]
run_b_idx=runs[previous_idx]
run_b_stop=runs[indices[$((index + 2))]]
unset runs[previous_idx]
while ((run_a_idx < run_a_stop && run_b_idx < run_b_stop)); do
if [[ "${merge[run_a_idx]}" < "${merge[run_b_idx]}" ]]; then
output_reference[merged_idx++]="${merge[run_a_idx++]}"
else
output_reference[merged_idx++]="${merge[run_b_idx++]}"
fi
done
while ((run_a_idx < run_a_stop)); do
output_reference[merged_idx++]="${merge[run_a_idx++]}"
done
while ((run_b_idx < run_b_stop)); do
output_reference[merged_idx++]="${merge[run_b_idx++]}"
done
done
done
}
declare -ar input=({z..a}{z..a})
declare -a output
mergesort input output
echo "${input[@]}"
echo "${output[@]}"
저보다 먼저 대답해주신 분들께 감사드립니다.뛰어난 입력, bash 문서 및 다른 스텝의 아이디어를 사용하여 IFS 변경 없이 완벽하게 기능합니다.
array=("a \n c" b f "3 5")
프로세스 치환을 사용하여 bash > v4.4 With EOL 문자로 어레이 읽기
readarray -t sorted < <(sort < <(printf '%s\n' "${array[@]}"))
프로세스 치환을 사용하여 null 문자와 함께 bash > v4.4에서 어레이를 읽습니다.
readarray -td '' sorted < <(sort -z < <(printf '%s\0' "${array[@]}"))
마지막으로 다음 방법으로 검증합니다.
printf "[%s]\n" "${sorted[@]}"
출력은
[3 5]
[a \n c]
[b]
[f]
두 솔루션 모두 같은 결과가 나오는데 첫 번째 솔루션이 삽입형 /n에서는 제대로 작동하지 않을 것이기 때문에 삽입형 /n에 대한 올바른 테스트인지 알려주시기 바랍니다.
Bash에서 외부 분류 프로그램이 필요할지 확신이 안 서네요.
간단한 버블 정렬 알고리즘의 실장은 다음과 같습니다.
function bubble_sort()
{ #
# Sorts all positional arguments and echoes them back.
#
# Bubble sorting lets the heaviest (longest) element sink to the bottom.
#
local array=($@) max=$(($# - 1))
while ((max > 0))
do
local i=0
while ((i < max))
do
if [ ${array[$i]} \> ${array[$((i + 1))]} ]
then
local t=${array[$i]}
array[$i]=${array[$((i + 1))]}
array[$((i + 1))]=$t
fi
((i += 1))
done
((max -= 1))
done
echo ${array[@]}
}
array=(a c b f 3 5)
echo " input: ${array[@]}"
echo "output: $(bubble_sort ${array[@]})"
이것은 다음을 인쇄해야 한다.
input: a c b f 3 5
output: 3 5 a b c f
a=(e b 'c d')
shuf -e "${a[@]}" | sort >/tmp/f
mapfile -t g </tmp/f
좋은 답변입니다.많이 배웠어요.그것들을 다 읽고 난 후, 나는 출사표를 던져야겠다고 결심했다.방법이라고 셸해석은 않기 도 모릅니다만, ).printf ★★★★★★★★★★★★★★★★★」sort한 이 처리됩니다: 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예, 예.
a=(3 "2 a" 1) # Setup!
IFS=$'\n' b=( $(printf "%s\n" "${a[@]}" | sort) ); unset IFS # Sort!
printf "'%s' " "${b[@]}"; # Success!
출력:
'1' '2 a' '3'
주의:
그 IFS 변경의 범위는 그 행에 한정됩니다.
어레이에 공백이 없는 것을 알고 있는 경우는, 그 어레이에 공백이 필요 없습니다.IFS★★★★★★ 。
영감은 @yas의 답변과 @Alcamtar 댓글에서 나왔다.
편집
오, 나는 내 대답보다 더 짧은 실제로 받아들여진 대답을 놓쳤다.도!
IFS=$'\n' sorted=($(sort <<<"${array[*]}")); unset IFS
결과, 「 」는, 「 」, 「 」, 「 」가 됩니다.unset는 명령어가 없는 변수 할당이기 때문에 필요합니다.
이 답변에는 Globbing에 관한 흥미로운 내용이 포함되어 있으며 어레이에 와일드카드가 포함되어 있다면 관련이 있을 수 있습니다.또한 무슨 일이 일어나고 있는지에 대한 자세한 설명도 있습니다.
편집 2
에는 GNU를 사용하여 .\0LF를 사용하다되었을 때, 이 「어레이」로 않습니다.\0「」의IFS=$'\0'껍데기는 좋아하지 않고 제대로 분해되지 않습니다.
array=(z 'b c'); { set "${array[@]}"; printf '%s\n' "$@"; } \
| sort \
| mapfile -t array; declare -p array
declare -a array=([0]="b c" [1]="z")
- 함수 " " 를 엽니다.
{...}인수를$1,$2참조) - (예:
set "${array[@]}"는 n번째 배열 인수를 n번째 위치 인수에 복사합니다.따옴표는 배열 요소에 포함될 수 있는 공백을 유지합니다). - 인수를 각위 ( ((((((((((((((((((:
printf '%s\n' "$@"아, 네, 네, 그렇습니다.따옴표는 각 위치 인수에 포함될 수 있는 공백을 유지합니다.) - ★★★★★★★★★★★★★★★.
sort그 역할을 합니다. - 하여 스트림을 " 스스스스스
mapfile -t array.array및-t\n각행서서각 。 - 어레이를 덤프하여 정렬된 어레이를 표시합니다.
기능으로서:
set +m
shopt -s lastpipe
sort_array() {
declare -n ref=$1
set "${ref[@]}"
printf '%s\n' "$@"
| sort \
| mapfile -t $ref
}
그리고나서
array=(z y x); sort_array array; declare -p array
declare -a array=([0]="x" [1]="y" [2]="z")
UNIX의 모든 전문가에게 갈기갈기 찢겨질 것을 기대하고 있습니다. :)
sorted=($(echo ${array[@]} | tr " " "\n" | sort))
bash 각 .bash / linux에 한 명령줄 합니다. sort의 매우 은 다음과 같은 작업을 따라서 위의 매우 간단한 파이프라인은 다음과 같은 작업을 수행합니다.
에코 어레이 콘텐츠 --> 공간을 줄바꿈 --> 정렬
$()를 에코하는 입니다.
($())는 ''를 배열하여 배열하는 입니다.
주의: @sorontar가 다른 질문에 대한 코멘트에서 언급했듯이:
sorted=sorted(...) 부분은 "sorted and glob" 연산자를 사용하고 있습니다.glob을 꺼야 합니다: set -f 또는 set -o noglob 또는 shopt -op noglob 또는 *와 같은 배열 요소가 파일 목록으로 확장됩니다.
언급URL : https://stackoverflow.com/questions/7442417/how-to-sort-an-array-in-bash
'programing' 카테고리의 다른 글
| 텍스트와 varchar의 차이(문자에 따라 다름) (0) | 2023.04.11 |
|---|---|
| Windows에서 msysgit을 사용하여 Git 서버 설정 (0) | 2023.04.11 |
| WPF 목록 상자의 열을 모든 항목에 대해 같은 너비로 만들려면 어떻게 해야 합니까? (0) | 2023.04.11 |
| NSUserDefaults에 사용자 지정 개체를 저장하는 방법 (0) | 2023.04.11 |
| 목록의 모든 요소가 고유한지 확인 (0) | 2023.04.11 |