bash - reordena a matriz como se fosse um círculo definindo um ponto de partida

2

Eu uso esse tipo de configuração em um script:

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

a opção --setstart permite-me escolher onde começar a ler o array (o comando sed foi o que eu pude pensar no momento para resolver este problema).

O próprio script é executado sem as impressões de opção: C G D A E B Se eu definir um valor com --setstart , obtenho a matriz impressa a partir desse ponto, portanto, --setstart D imprimiria: D A E B .

Como eu poderia introduzir uma opção que poderia imprimir o array como um ciclo, de modo que o recorte parcial no começo seria colocado no fim. Então, digamos que a configuração D imprima: D A E B C G ?

    
por nath 22.12.2017 / 13:35

2 respostas

2

Usando a expansão de subcadeia Bash (subarray) (por exemplo, ${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[@]}" 

Aqui estamos colocando o array original em um array recém-ordenado apenas para ilustrar. (Eu omiti algumas verificações de limite óbvias e coisas do tipo.)

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

Atualização: modifiquei o script acima para lidar com as compensações negativas (inspiradas na resposta da ikkachu ) ...

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

Atualização 2: Para que o script aceite uma das letras "A" a "F", que está mais de acordo com o exemplo da pergunta, substitua start=$1 por:

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

É claro que, se você não tiver uma matriz de letras bem ordenada, precisará de algo mais como isso, que manipulará elementos arbitrários de matriz:

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

Use o modulo. Bash / 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 inicia a indexação de array a partir de 1, então precisaria de uma pequena adaptação. O primeiro parâmetro de linha de comando define a posição inicial start , que pode ser negativa:

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

Deve ser simples o suficiente para modificá-lo para encontrar o ponto inicial por valor.

    
por 22.12.2017 / 13:52