bash - 通过设置起点重新排序数组,就好像它是一个圆一样

bash - 通过设置起点重新排序数组,就好像它是一个圆一样

我在脚本中使用这种设置:

#!/bin/bash

array=(C G D A E B)

if [[ "$1" = "--setstart" ]] || [[ "$1" = "-s" ]]; then
    if [ -n "$2" ]; then

        array=($(sed "s/.*$2 /$2 /" <<< "${array[@]}"))

    else
        printf "\nno argument...!\n"
    fi
fi

for a in "${array[@]}"; do
    printf "%s " "$a"
done    
echo

--setstart选项使我能够选择从哪里开始读取数组(该sed命令是我目前能想到的解决此问题的方法)。

脚本本身在没有选项 prints: 的情况下运行,C G D A E B 如果我设置一个值,--setstart我会从该点打印数组,所以--setstart D会 print: D A E B

我怎样才能引入一个选项,将其打印array为一个循环,这样开头剪切的部分就会被放到最后。假设设置D会打印:D A E B C G?

答案1

使用 Bash 子字符串(子数组)扩展(即${parameter:offset:length})...

array=(A B C D E F)

start=$1
# handle negative offsets
[[ $start -lt 0 ]] && start=$((${#array[@]} + start))

# the star of the show, create array2 from two sub-arrays of array
array2=("${array[@]:$start}" "${array[@]:0:$start}")

echo "${array2[@]}" 

这里我们将原始数组放入新排序的数组中只是为了说明。 (我省略了一些明显的边界检查等。)

$ ./rotate.sh 3
D E F A B C

更新:我修改了上面的脚本来处理负偏移量(受到启发伊卡丘的回答)...

$ ./rotate.sh -2
E F A B C D

更新2:对于接受字母“A”到“F”之一的脚本(这更符合问题中的示例),请替换start=$1为:

# Convert [A-F] to ASCII code then normalize to [0-5]
LC_CTYPE=C start=$(( $(printf %d "'$1") - 65 ))

当然,如果你没有一个有序的字母数组,那么你需要更多类似这样的东西来处理任意数组元素:

idx=0
for elem in "${array[@]}"; do
    [[ $elem = $1 ]] && break
    ((idx++))
done
start=$idx

答案2

使用模数。重击/ksh:

$ cat rotate.sh
#!/bin/bash
array=(A B C D E F)
n=${#array[@]}
start=${1-0}
i=0;
while (( i < n )) ; do
    printf "%s " "${array[(start + i) % n]}"
    (( i++ ))
done
echo

Zsh 从 1 开始数组索引,因此需要进行一些小的调整。第一个命令行参数设置起始位置start,可以为负数:

$ ./rotate.sh 2
C D E F A B 

修改它以按值查找起点应该很简单。

相关内容