如何在 Bash 中对数组进行排序

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7442417/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 21:02:29  来源:igfitidea点击:

How to sort an array in Bash

arraysbashshellsorting

提问by u32004

I have an array in Bash, for example:

我在 Bash 中有一个数组,例如:

array=(a c b f 3 5)

I need to sort the array. Not just displaying the content in a sorted way, but to get a new array with the sorted elements. The new sorted array can be a completely new one or the old one.

我需要对数组进行排序。不仅仅是以排序的方式显示内容,而是获取一个包含排序元素的新数组。新的排序数组可以是全新的,也可以是旧的。

回答by antak

You don't really need all that much code:

你真的不需要那么多代码:

IFS=$'\n' sorted=($(sort <<<"${array[*]}"))
unset IFS

Supports whitespace in elements (as long as it's not a newline), andworks in Bash 3.x.

支持元素中的空格(只要它不是换行符),并且适用于 Bash 3.x。

e.g.:

例如:

$ array=("a c" b f "3 5")
$ IFS=$'\n' sorted=($(sort <<<"${array[*]}")); unset IFS
$ printf "[%s]\n" "${sorted[@]}"
[3 5]
[a c]
[b]
[f]

Note:@sorontar has pointed outthat care is required if elements contain wildcards such as *or ?:

注意:@sorontar指出,如果元素包含通配符,例如*或,则需要小心?

The sorted=($(...)) part is using the "split and glob" operator. You should turn glob off: set -for set -o noglobor shopt -op noglobor an element of the array like *will be expanded to a list of files.

sorted=($(...)) 部分使用“split and glob”运算符。您应该关闭 glob: set -for set -o noglobor shopt -op noglobor 数组的一个元素,例如*将被扩展为文件列表。

What's happening:

发生了什么:

The result is a culmination six things that happen in this order:

结果是按此顺序发生的六件事达到顶峰:

  1. IFS=$'\n'
  2. "${array[*]}"
  3. <<<
  4. sort
  5. sorted=($(...))
  6. unset IFS
  1. IFS=$'\n'
  2. "${array[*]}"
  3. <<<
  4. sort
  5. sorted=($(...))
  6. unset IFS

First, the IFS=$'\n'

首先, IFS=$'\n'

This is an important part of our operation that affects the outcome of 2 and 5 in the following way:

这是我们操作的一个重要部分,它通过以下方式影响 2 和 5 的结果:

Given:

鉴于:

  • "${array[*]}"expands to every element delimited by the first character of IFS
  • sorted=()creates elements by splitting on every character of IFS
  • "${array[*]}"扩展到由第一个字符分隔的每个元素 IFS
  • sorted=()通过拆分每个字符来创建元素 IFS

IFS=$'\n'sets things upso that elements are expanded using a new lineas the delimiter, and then later created in a way that each line becomes an element. (i.e. Splitting on a new line.)

IFS=$'\n'设置内容,以便使用新行作为分隔符扩展元素,然后以每行成为一个元素的方式创建。(即在新行上拆分。)

Delimiting by a new line is important because that's how sortoperates (sorting per line). Splitting by onlya new line is not-as-important, but is needed preserve elements that contain spaces or tabs.

以新行分隔很重要,因为这就是sort操作方式(每行排序)。由新行拆分并不重要,但需要保留包含空格或制表符的元素。

The default value of IFSis a space, a tab, followed by a new line, and would be unfit for our operation.

的默认值IFS一个空格一个制表符,后跟一个新行,不适合我们的操作。

Next, the sort <<<"${array[*]}"part

接下来,sort <<<"${array[*]}"部分

<<<, called here strings, takes the expansion of "${array[*]}", as explained above, and feeds it into the standard input of sort.

<<<在此处称为strings,采用 的扩展"${array[*]}",如上所述,并将其提供给 的标准输入sort

With our example, sortis fed this following string:

在我们的示例中,sort输入以下字符串:

a c
b
f
3 5

Since sortsorts, it produces:

由于sortsorts,它产生:

3 5
a c
b
f

Next, the sorted=($(...))part

接下来,sorted=($(...))部分

The $(...)part, called command substitution, causes its content (sort <<<"${array[*]}) to run as a normal command, while taking the resulting standard outputas the literal that goes where ever $(...)was.

$(...)部分称为命令替换,使其内容 ( sort <<<"${array[*]}) 作为普通命令运行,同时将生成的 标准输出作为原先所在位置的文字$(...)

In our example, this produces something similar to simply writing:

在我们的示例中,这会产生类似于简单编写的内容:

sorted=(3 5
a c
b
f
)

sortedthen becomes an array that's created by splitting this literal on every new line.

sorted然后成为通过在每个新行上拆分此文字创建的数组。

Finally, the unset IFS

最后, unset IFS

This resets the value of IFSto the default value, and is just good practice.

这会将 的值重置为IFS默认值,这只是一种很好的做法。

It's to ensure we don't cause trouble with anything that relies on IFSlater in our script. (Otherwise we'd need to remember that we've switched things around--something that might be impractical for complex scripts.)

这是为了确保我们不会IFS对脚本中稍后依赖的任何内容造成麻烦。(否则我们需要记住我们已经改变了一些东西——这对于复杂的脚本来说可能是不切实际的。)

回答by sehe

Original response:

原回复:

array=(a c b "f f" 3 5)
readarray -t sorted < <(for a in "${array[@]}"; do echo "$a"; done | sort)

output:

输出:

$ for a in "${sorted[@]}"; do echo "$a"; done
3
5
a
b
c
f f

Notethis version copes with values that contains special characters or whitespace (exceptnewlines)

请注意,此版本处理包含特殊字符或空格的值(换行符除外

Notereadarray is supported in bash 4+.

注意bash 4+ 支持 readarray。



EditBased on the suggestion by @Dimitre I had updated it to:

编辑根据@Dimitre 的建议,我已将其更新为:

readarray -t sorted < <(printf '%s
#!/bin/bash

# quicksorts positional arguments
# return is in array qsort_ret
qsort() {
   local pivot i smaller=() larger=()
   qsort_ret=()
   (($#==0)) && return 0
   pivot=
   shift
   for i; do
      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[@]}" | sort -z | xargs -0n1)

which has the benefit of even understanding sortingelements with newline characters embedded correctly. Unfortunately, as correctly signaled by @ruakh this didn't mean the the result of readarraywould be correct, because readarrayhas no option to use NULinstead of regular newlinesas line-separators.

它的好处是甚至可以理解正确嵌入换行符的排序元素。不幸的是,正如@ruakh 正确表示的那样,这并不意味着结果readarray正确的,因为readarray没有选择使用NUL代替常规换行符作为行分隔符。

回答by gniourf_gniourf

Here's a pure Bash quicksort implementation:

这是一个纯 Bash 快速排序实现:

$ 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")'

Use as, e.g.,

用作,例如,

#!/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
}

This implementation is recursive… so here's an iterative quicksort:

这个实现是递归的……所以这是一个迭代快速排序:

#!/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=
   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
}

In both cases, you can change the order you use: I used string comparisons, but you can use arithmetic comparisons, compare wrt file modification time, etc. just use the appropriate test; you can even make it more generic and have it use a first argument that is the test function use, e.g.,

在这两种情况下,您都可以更改您使用的顺序:我使用字符串比较,但您可以使用算术比较,比较wrt文件修改时间等,只需使用适当的测试即可;你甚至可以让它更通用,并让它使用作为测试函数使用的第一个参数,例如,

compare_mtime() { [[  -nt  ]]; }

Then you can have this comparison function:

然后你可以有这个比较功能:

$ qsort compare_mtime *
$ declare -p qsort_ret

and use:

并使用:

array=(a c b f 3 5)
sorted=($(printf '%s\n' "${array[@]}"|sort))

to have the files in current folder sorted by modification time (newest first).

让当前文件夹中的文件按修改时间排序(最新的在前)。

NOTE. These functions are pure Bash! no external utilities, and no subshells! they are safe wrt any funny symbols you may have (spaces, newline characters, glob characters, etc.).

笔记。这些函数是纯 Bash!没有外部实用程序,也没有子shell!它们对于您可能拥有的任何有趣符号(空格、换行符、通配符等)都是安全的。

回答by Dimitre Radoulov

If you don't need to handle special shell characters in the array elements:

如果不需要处理数组元素中的特殊 shell 字符:

% array=('a a' c b f 3 5); printf '%s\n' "${(o)array[@]}" 
3
5
a a
b
c
f

With bashyou'll need an external sorting program anyway.

无论如何,使用bash您将需要一个外部排序程序。

With zshno external programs are needed and special shell characters are easily handled:

使用zsh不需要外部程序,并且可以轻松处理特殊的 shell 字符:

readarray -t a_out < <(printf '%s\n' "${a_in[@]}" | sort)

kshhas set -sto sort ASCIIbetically.

ksh必须set -sASCII进行排序。

回答by mklement0

tl;dr:

tl;博士

Sort array a_inand store the result in a_out(elements must not have embeddednewlines[1]):

对数组进行排序a_in并将结果存储在a_out(元素不得嵌入换行符[1]):

Bash v4+:

Bash v4+:

IFS=$'\n' read -d '' -r -a a_out < <(printf '%s\n' "${a_in[@]}" | sort)

Bash v3:

Bash v3:

#!/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[@]}"

Advantages over antak's solution:

antak 解决方案相比的优势:

  • You needn't worry about accidental globbing (accidental interpretation of the array elements as filename patterns), so no extra command is needed to disable globbing (set -f, and set +fto restore it later).

  • You needn't worry about resetting IFSwith unset IFS.[2]

  • 您不必担心意外的 globbing(意外地将数组元素解释为文件名模式),因此不需要额外的命令来禁用 globbing ( set -f,并set +f在以后恢复它)。

  • 您无需担心IFS使用unset IFS. [2]



Optional reading: explanation and sample code

可选阅读:解释和示例代码

The above combines Bash code with external utility sortfor a solution that works with arbitrary single-line elementsand either lexical or numerical sorting (optionally by field):

上面将 Bash 代码与外部实用程序相结合,sort用于处理任意单行元素词法或数字排序(可选按字段)的解决方案

  • Performance: For around 20 elements or more, this will be fasterthan a pure Bash solution- significantly and increasingly so once you get beyond around 100 elements.
    (The exact thresholds will depend on your specific input, machine, and platform.)

    • The reason it is fast is that it avoids Bash loops.
  • printf '%s\n' "${a_in[@]}" | sortperforms the sorting(lexically, by default - see sort's POSIX spec):

    • "${a_in[@]}"safely expands to the elements of array a_inas individual arguments, whatever they contain (including whitespace).

    • printf '%s\n'then prints each argument - i.e., each array element - on its own line, as-is.

  • Note the use of a process substitution (<(...))to provide the sorted output as input to read/ readarray(via redirection to stdin, <), because read/ readarraymust run in the currentshell(must not run in a subshell) in order for output variable a_outto be visible to the current shell (for the variable to remain defined in the remainder of the script).

  • Reading sort's output into an array variable:

    • Bash v4+: readarray -t a_outreads the individual lines output by sortinto the elements of array variable a_out, without including the trailing \nin each element (-t).

    • Bash v3: readarraydoesn't exist, so readmust be used:
      IFS=$'\n' read -d '' -r -a a_outtells readto read into array (-a) variable a_out, reading the entire input, across lines (-d ''), but splitting it into array elements by newlines (IFS=$'\n'. $'\n', which produces a literal newline (LF), is a so-called ANSI C-quoted string).
      (-r, an option that should virtually always be used with read, disables unexpected handling of \characters.)

  • 性能:对于大约 20 个或更多元素,这将比纯 Bash 解决方案更快- 一旦超过大约 100 个元素,这将变得越来越明显。
    (确切的阈值将取决于您的特定输入、机器和平台。)

    • 它很快的原因是它避免了 Bash 循环
  • printf '%s\n' "${a_in[@]}" | sort执行排序(在词汇上,默认情况下 - 请参阅sort的 POSIX 规范):

    • "${a_in[@]}"安全地扩展到数组元素a_in作为单独的参数,无论它们包含什么(包括空格)。

    • printf '%s\n'然后按原样在其自己的行上打印每个参数 - 即每个数组元素。

  • 请注意使用进程替换 ( <(...))将排序的输出提供为read/ 的输入readarray(通过重定向到标准输入<),因为read/readarray必须在当前shell 中运行(不得在子 shell 中运行)才能使输出变量a_out可见到当前 shell(使变量在脚本的其余部分中保持定义)。

  • sort的输出读入数组变量

    • Bash v4+:readarray -t a_out将 by 输出的各个行读sort入数组 variable 的元素中a_out,不包括\n每个元素中的尾随( -t)。

    • Bash v3:readarray不存在,所以read必须使用:
      IFS=$'\n' read -d '' -r -a a_out告诉read读入数组 ( -a) 变量a_out,读取整个输入,跨行 ( -d ''),但通过换行符将其拆分为数组元素 ( IFS=$'\n'. $'\n',产生文字换行符 (LF ),是所谓的ANSI C 引用字符串)。
      -r,实际上应该始终与 一起使用的选项read,禁用\字符的意外处理。)

Annotated sample code:

带注释的示例代码:

*
10
5
a c
b
f

Due to use of sortwithout options, this yields lexicalsorting (digits sort before letters, and digit sequences are treated lexically, not as numbers):

由于使用了sort不带选项,这会产生词法排序(数字在字母之前排序,并且数字序列在词法上被处理,而不是作为数字):

*
a c
b
f
5
10

If you wanted numericalsorting by the 1st field, you'd use sort -k1,1ninstead of just sort, which yields (non-numbers sort before numbers, and numbers sort correctly):

如果您想按第一个字段进行数字排序,您可以使用sort -k1,1n而不仅仅是sort,它会产生(非数字排序在数字之前,并且数字正确排序):

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[@]}


[1] To handle elements with embedded newlines, use the following variant (Bash v4+, with GNUsort):
readarray -d '' -t a_out < <(printf '%s\0' "${a_in[@]}" | sort -z).
Micha? Górny's helpful answerhas a Bash v3 solution.

[1] 要处理带有嵌入换行符的元素,请使用以下变体(Bash v4+,带有GNUsort):
readarray -d '' -t a_out < <(printf '%s\0' "${a_in[@]}" | sort -z).
米夏?Górny 的有用答案有一个 Bash v3 解决方案。

[2] While IFSisset in the Bash v3 variant, the change is scoped to the command.
By contrast, what follows IFS=$'\n'?in antak's answer is an assignmentrather than a command, in which case the IFSchange is global.

[2]当IFS在Bash V3变体设置,所述变化是作用域到命令
相比之下,IFS=$'\n'?antak 的回答中的内容是赋值而不是命令,在这种情况下,IFS更改是global

回答by Andreas Spindler

In the 3-hour train trip from Munich to Frankfurt (which I had trouble to reach because Oktoberfest starts tomorrow) I was thinking about my first post. Employing a global array is a much better idea for a general sort function. The following function handles arbitary strings (newlines, blanks etc.):

在从慕尼黑到法兰克福的 3 小时火车旅行中(由于慕尼黑啤酒节明天开始,我很难到达)我正在考虑我的第一篇文章。对于通用排序函数,使用全局数组是一个更好的主意。以下函数处理任意字符串(换行符、空格等):

3 5 a b c z y

This prints:

这打印:

BSORT=(a c b 'z y' 3 5) 
bubble_sort
echo ${BSORT[@]}

The same output is created from

相同的输出是从

local e new_array=()
while IFS= read -r -d '' e; do
    new_array+=( "${e}" )
done < <(printf "%s
for e in "${array[@]}"; do
    printf "%s
#!/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
" "${e}" done
" "${array[@]}" | LC_ALL=C sort -z)

Note that probably Bash internally uses smart-pointers, so the swap-operation couldbe cheap (although I doubt it). However, bubble_sortdemonstrates that more advanced functions like merge_sortare also in the reach of the shell language.

请注意,Bash 内部可能使用智能指针,因此交换操作可能很便宜(尽管我对此表示怀疑)。但是,bubble_sort演示了更高级的功能,例如merge_sortshell 语言也可以使用。

回答by Micha? Górny

Another solution that uses external sortand copes with anyspecial characters (except for NULs :)). Should work with bash-3.2 and GNU or BSD sort(sadly, POSIX doesn't include -z).

另一种使用外部sort并处理任何特殊字符的解决方案(NUL 除外:))。应该适用于 bash-3.2 和 GNU 或 BSD sort(遗憾的是,POSIX 不包括-z)。

echo ${array[@]} | awk 'BEGIN{RS=" ";} {print }' | sort

First look at the input redirection at the end. We're using printfbuilt-in to write out the array elements, zero-terminated. The quoting makes sure array elements are passed as-is, and specifics of shell printfcause it to reuse the last part of format string for each remaining parameter. That is, it's equivalent to something like:

先看最后的输入重定向。我们使用printf内置来写出数组元素,以零结尾。引用确保数组元素按原样传递,shell 的细节printf导致它为每个剩余参数重用格式字符串的最后一部分。也就是说,它相当于:

3
5
a
b
c
f

The null-terminated element list is then passed to sort. The -zoption causes it to read null-terminated elements, sort them and output null-terminated as well. If you needed to get only the unique elements, you can pass -usince it is more portable than uniq -z. The LC_ALL=Censures stable sort order independently of locale — sometimes useful for scripts. If you want the sortto respect locale, remove that.

然后将空终止元素列表传递给sort。该-z选项使其读取以空字符结尾的元素,对它们进行排序并输出以空字符结尾的元素。如果您只需要获取唯一元素,则可以通过,-u因为它比uniq -z. 该LC_ALL=C独立保证稳定的排序顺序的语言环境-有时脚本很有用。如果您希望sort尊重语言环境,请将其删除。

The <()construct obtains the descriptor to read from the spawned pipeline, and <redirects the standard input of the whileloop to it. If you need to access the standard input inside the pipe, you may use another descriptor — exercise for the reader :).

<()构造从生成的管道中获取要读取的描述符,并将循环<的标准输入重定向while到它。如果您需要访问管道内的标准输入,您可以使用另一个描述符——读者练习:)。

Now, back to the beginning. The readbuilt-in reads output from the redirected stdin. Setting empty IFSdisables word splitting which is unnecessary here — as a result, readreads the whole 'line' of input to the single provided variable. -roption disables escape processing that is undesired here as well. Finally, -d ''sets the line delimiter to NUL — that is, tells readto read zero-terminated strings.

现在,回到起点。该read内置读取从标准输入重定向输出。设置为空IFS会禁用这里不必要的分词——因此,read读取输入的整个“行”到单个提供的变量。-r选项禁用这里不希望的转义处理。最后,-d ''将行分隔符设置为 NUL — 即告诉read读取以零结尾的字符串。

As a result, the loop is executed once for every successive zero-terminated array element, with the value being stored in e. The example just puts the items in another array but you may prefer to process them directly :).

因此,循环对每个连续的以零结尾的数组元素执行一次,并将值存储在 中e。该示例只是将项目放在另一个数组中,但您可能更喜欢直接处理它们:)。

Of course, that's just one of the many ways of achieving the same goal. As I see it, it is simpler than implementing complete sorting algorithm in bash and in some cases it will be faster. It handles all special characters including newlines and should work on most of the common systems. Most importantly, it may teach you something new and awesome about bash :).

当然,这只是实现同一目标的众多方法之一。在我看来,它比在 bash 中实现完整的排序算法更简单,在某些情况下它会更快。它处理包括换行符在内的所有特殊字符,并且应该适用于大多数常见系统。最重要的是,它可能会教你一些关于 bash 的新的和很棒的东西:)。

回答by MathQues

min sort:

最小排序:

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 -> $?"

回答by rsingh

try this:

尝试这个:

array=(a c b f 3 5)
for el in "${array[@]}"; do
    sexy_int "$el"
    sorted[$?]="$el"
done

echo "${sorted[@]}"

Output will be:

输出将是:

##代码##

Problem solved.

问题解决了。

回答by Xiè Jìléi

If you can compute a unique integer for each element in the array, like this:

如果您可以为数组中的每个元素计算一个唯一的整数,如下所示:

##代码##

then, you can use these integers as array indexes, because Bash always use sparse array, so no need to worry about unused indexes:

然后,你可以将这些整数用作数组索引,因为 Bash 总是使用稀疏数组,因此无需担心未使用的索引:

##代码##
  • Pros. Fast.
  • Cons. Duplicated elements are merged, and it can be impossible to map contents to 32-bit unique integers.
  • 优点。快速地。
  • 缺点。重复的元素被合并,并且不可能将内容映射到 32 位唯一整数。