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

问题描述

你真的不需要那么多代码

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指出,如果元素包含通配符,例如*or,则需要小心?

sorted=($(…)) 部分使用“split and glob”运算符。您应该关闭 glob:set -fset -o noglobshopt -op noglob或数组的元素,例如*将扩展为文件列表。

发生了什么:

结果是按此顺序发生的六件事的高潮:

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

首先,IFS=$'\n'

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

鉴于:

  • "${array[*]}"扩展到由第一个字符分隔的每个元素IFS
  • sorted=()通过分割每个字符来创建元素IFS

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

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

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

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

<<<,这里称为 strings"${array[*]}" ,如上所述,接受 的扩展,并将其馈送到 的标准输入中sort

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

a c
b
f
3 5

由于sort sorts ,它产生:

3 5
a c
b
f

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

$(...)部分称为 命令替换 ,导致其内容 ( sort <<<"${array[*]}) 像普通命令一样运行,同时将生成标准输出 作为原文本$(...)

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

sorted=(3 5
a c
b
f
)

sorted然后成为一个数组,通过在每一行上拆分这个文字来创建。

最后,unset IFS

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

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

解决方法

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

array=(a c b f 3 5)

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