我试图弄清楚如何创建一个可以将数组作为参数并对其进行排序的函数。我认为这是通过位置变量完成的,但我不确定。
答案1
巴什
我认为bash
还没有任何内置支持。选项是手动实现排序算法或调用sort
排序算法。
如果我们认为数组元素可以包含除 0 之外的任何字节值bash
,为了可靠地做到这一点,我们需要传递 NUL 分隔的元素列表并使用选项-z
(sort
非标准但在 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
使用,进行简单排序sort
:tr
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[@]}