如何创建一个可以在 bash 中对数组进行排序的函数?

如何创建一个可以在 bash 中对数组进行排序的函数?

我试图弄清楚如何创建一个可以将数组作为参数并对其进行排序的函数。我认为这是通过位置变量完成的,但我不确定。

答案1

巴什

我认为bash还没有任何内置支持。选项是手动实现排序算法或调用sort排序算法。

如果我们认为数组元素可以包含除 0 之外的任何字节值bash,为了可靠地做到这一点,我们需要传递 NUL 分隔的元素列表并使用选项-zsort非标准但在 GNU 排序或 FreeBSD 排序中可用) )。

bash-4.4(2016 年 9 月发布)使它变得更容易,因为它-d在其内置中引入了一个选项readarray来指定分隔符。

将数组排序a为数组b

readarray -td '' b < <(printf '%s\0' "${a[@]}" | sort -z)

会可靠地对数组进行排序。使用-n,-r选项按sort数字或反向排序(或支持的任何排序条件sort)。

要实现您的sortarray函数(对按名称作为参数传递的所有数组进行排序):

sortarray() for array do
  eval '((${#'"$array"'[@]} <= 1))' || readarray -td '' "$array" < <(
    eval "printf '%s\0' \"\${$array[@]}\" | sort -z")
done

对于早期版本的bash,您可以read -d在循环中使用来实现相同的目的:

b=()
while IFS= read -rd '' item; do b+=("$item"); done < <(
  printf '%s\0' "${a[@]}" | sort -z)

对于sortarray函数:

sortarray() for array do eval '
  tmp=()
  while IFS= read -rd "" item; do tmp+=("$item"); done < <(
    printf "%s\0" "${'"$array"'[@]}" | sort -z)
  '"$array"'=("${tmp[@]}")'
done

桀骜

Zsh 具有对数组排序的内置支持。

您可以使用o参数扩展标志按词法排序(O用于逆序)。您可以添加n标志以按数字排序:

$ a=('' 12 2 d é f $'a\nb')
$ printf '<%s>\n' "${(@o)a}"
<>
<12>
<2>
<a
b>
<d>
<é>
<f>
$ printf '<%s>\n' "${(@no)a}"
<>
<2>
<12>
<a
b>
<d>
<é>
<f>

在尚未区分大小写排序的语言环境中,您还可以i为此添加标志。

分配给数组:

b=("${(@o)a}")

所以一个sortarray函数会是这样的:

sortarray() for array do eval "$array=(\"\${(@o)$array}\")"; done

AT&T ksh(ksh88 或 ksh93,在某些系统上都可以作为 sh 找到)

set -s -- "${a[@]}"
b=("$@")

set -s对参数列表进行排序并将其存储在位置参数中。该顺序是词汇的。

函数sortarray可以是:

sortarray() for array do
  eval 'set -s -- "${'"$array"'[@]}"; '"$array"'=("$@")'
done

答案2

使用,进行简单排序sorttr

arr=($(for i in {0..9}; do echo $((RANDOM%100)); done))
echo ${arr[*]}| tr " " "\n" | sort -n | tr "\n" " "

进入一个新数组:

arr2=($(echo ${arr[*]}| tr " " "\n" | sort -n))

tr没有/的帮助sort,例如冒泡排序:

#!/bin/bash    
sort () {
    for ((i=0; i <= $((${#arr[@]} - 2)); ++i))
    do
        for ((j=((i + 1)); j <= ((${#arr[@]} - 1)); ++j))
        do
            if [[ ${arr[i]} -gt ${arr[j]} ]]
            then
                # echo $i $j ${arr[i]} ${arr[j]}
                tmp=${arr[i]}
                arr[i]=${arr[j]}
                arr[j]=$tmp         
            fi
        done
    done
}
# arr=(6 5 68 43 82 60 45 19 78 95)
arr=($(for i in {0..9}; do echo $((RANDOM%100)); done))
echo ${arr[@]}
sort ${arr[@]}
echo ${arr[@]}

对于 20 个数字,冒泡排序可能就足够了。

答案3

sortnums(){
    local OLDPWD IFS=' /'
    cd -- "$(mktemp -d)" || return
    touch -- $*;  ls -A
    cd - >/dev/null &&
    rm -rf -- "$OLDPWD"
}

这是一个稍微复杂一点、速度稍慢的版本,但它不会挤压重复项,并且会进行排序(尺寸合理)按数字顺序排列的十进制数字 - 不过(空间分割)其他字符串仍然排序,首先考虑字符串长度。为了处理通用字符串,您几乎肯定希望以g=[0-9]不同的方式设置 glob。

我会说实话 - 我会(或许)考虑对列表进行排序或者数字像这样,但我不会想到创建一个名称至少不适合段落的文件。所以它在空间上分裂。大多数情况下,这是正确的做法。然而,它也受到/像 null 一样对待的理智要求的阻碍。但无论如何,这只是为了好玩。

fs_sort(){
        local OLDPWD IFS=' /' opt="$-" g
        cd -- "$(mktemp -d)" || return
        set     -C                         ### noClobber for testable >
        for     g in    $*                 ### disallow any / reference
        do      until   command >" $g"     ### who needs dot glob?
                do      g=" $g"            ### '   1' lex== ' 1'
        done;   done    2>&1               ### -C is bitchy
                g=[0-9]                    ### now glob the array
        while   set -f *\ $g   &&          ### set it  &&
                <"$1" g+=? arr+=( $* )     ### <chk && (clean) it
        do      set +f;    done 2>&1       ### clear it
        set +fC "-${opts:--}"              ### put stuff where we found it
        cd - && rm  -rf -- "$OLDPWD"       ### don't leave our trash out
}       >/dev/null                         ### cd - is chatty

如果说这有什么教训的话,也许应该首先了解 bash 数组是多么肮脏的东西。如果数据只是保存在文件sort我们一开始就不会遇到任何问题。想象一下,如果您的登录 shell 只抓取了一小部分,那么在必要时维护重要的 shell 状态会容易得多。临时文件系统在启动时,将一个~/.sh目录复制到其中,然后复制回自关闭以来可能标记为粘滞的所有文件。全部你所在州的名字将像 一样简单地排序set *,并且您想要调用它们的任何实用程序都可以访问它们的内容,就像任何其他文件一样。

答案4

#! /bin/bash

array=('2' '7' '5' '9' '0')
sort=0
echo ${array[@]}
len=${#array[@]}
echo $len


for ((i=0; i<$len; i++))
do
    for((j=i+1; j<$len; j++))
    do
        if [ ${array[i]} -le ${array[j]} ]
        then
            continue
        else
            sort=${array[i]}
            array[i]=${array[j]}
            array[j]=$sort
        fi
    done
done
echo ${array[@]}

相关内容