AskOverflow.Dev

AskOverflow.Dev Logo AskOverflow.Dev Logo

AskOverflow.Dev Navigation

  • Início
  • system&network
  • Ubuntu
  • Unix
  • DBA
  • Computer
  • Coding
  • LangChain

Mobile menu

Close
  • Início
  • system&network
    • Recentes
    • Highest score
    • tags
  • Ubuntu
    • Recentes
    • Highest score
    • tags
  • Unix
    • Recentes
    • tags
  • DBA
    • Recentes
    • tags
  • Computer
    • Recentes
    • tags
  • Coding
    • Recentes
    • tags
Início / unix / Perguntas / 412868
Accepted
nath
nath
Asked: 2017-12-25 16:53:48 +0800 CST2017-12-25 16:53:48 +0800 CST 2017-12-25 16:53:48 +0800 CST

Bash - inverte uma matriz

  • 772

Existe uma maneira simples de inverter uma matriz?

#!/bin/bash

array=(1 2 3 4 5 6 7)

echo "${array[@]}"

então eu obteria: 7 6 5 4 3 2 1
em vez de:1 2 3 4 5 6 7

bash shell-script
  • 13 13 respostas
  • 35207 Views

13 respostas

  • Voted
  1. Cyrus
    2017-12-25T21:52:55+08:002017-12-25T21:52:55+08:00

    Outra abordagem não convencional:

    #!/bin/bash
    
    array=(1 2 3 4 5 6 7)
    
    f() { array=("${BASH_ARGV[@]}"); }
    
    shopt -s extdebug
    f "${array[@]}"
    shopt -u extdebug
    
    echo "${array[@]}"
    

    Resultado:

    7 6 5 4 3 2 1
    

    Se extdebugestiver habilitado, o array BASH_ARGVcontém em uma função todos os parâmetros posicionais na ordem inversa.

    • 27
  2. jimmij
    2017-12-25T17:52:53+08:002017-12-25T17:52:53+08:00

    Abordagem não convencional (nem tudo puro bash):

    • se todos os elementos em uma matriz tiverem apenas um caractere (como na pergunta), você poderá usar rev:

      echo "${array[@]}" | rev
      
    • por outro lado:

      printf '%s\n' "${array[@]}" | tac | tr '\n' ' '; echo
      
    • e se puder usar zsh:

      echo ${(Oa)array}
      
    • 24
  3. Best Answer
    roaima
    2017-12-25T17:07:57+08:002017-12-25T17:07:57+08:00

    Eu respondi à pergunta conforme escrita e este código inverte a matriz. (Imprimir os elementos na ordem inversa sem inverter a matriz é apenas um forloop de contagem regressiva do último elemento até zero.) Este é um algoritmo padrão de "trocar primeiro e último".

    array=(1 2 3 4 5 6 7)
    
    min=0
    max=$(( ${#array[@]} -1 ))
    
    while [[ min -lt max ]]
    do
        # Swap current first and last elements
        x="${array[$min]}"
        array[$min]="${array[$max]}"
        array[$max]="$x"
    
        # Move closer
        (( min++, max-- ))
    done
    
    echo "${array[@]}"
    

    Funciona para arrays de comprimento ímpar e par.

    • 18
  4. muru
    2017-12-26T01:20:51+08:002017-12-26T01:20:51+08:00

    Se você realmente deseja o inverso em outra matriz:

    reverse() {
        # first argument is the array to reverse
        # second is the output array
        declare -n arr="$1" rev="$2"
        for i in "${arr[@]}"
        do
            rev=("$i" "${rev[@]}")
        done
    }
    

    Então:

    array=(1 2 3 4)
    reverse array foo
    echo "${foo[@]}"
    

    Dá:

    4 3 2 1
    

    Isso deve lidar corretamente com os casos em que um índice de matriz está ausente, digamos que você tenha array=([1]=1 [2]=2 [4]=4), caso em que o loop de 0 para o índice mais alto pode adicionar elementos vazios adicionais.

    • 13
  5. user232326
    2017-12-25T17:12:07+08:002017-12-25T17:12:07+08:00

    Para trocar as posições do array no lugar (mesmo com arrays esparsos) (desde o bash 3.0):

    #!/bin/bash
    # Declare an sparse array to test:
    array=([5]=101 [6]=202 [10]=303 [11]=404 [20]=505 [21]=606 [40]=707)
    echo "Initial array values"
    declare -p array
    
    swaparray(){ local temp; temp="${array[$1]}"
                 array[$1]="${array[$2]}"
                 array[$2]="$temp"
               }
    
    ind=("${!array[@]}")                         # non-sparse array of indexes.
    
    min=-1; max="${#ind[@]}"                     # limits to one before real limits.
    while [[ min++ -lt max-- ]]                  # move closer on each loop.
    do
        swaparray "${ind[min]}" "${ind[max]}"    # Exchange first and last
    done
    
    echo "Final Array swapped in place"
    declare -p array
    echo "Final Array values"
    echo "${array[@]}"
    

    Na execução:

    ./script
    Initial array values
    declare -a array=([5]="101" [6]="202" [10]="303" [11]="404" [20]="505" [21]="606" [40]="707")
    
    Final Array swapped in place
    declare -a array=([5]="707" [6]="606" [10]="505" [11]="404" [20]="303" [21]="202" [40]="101")
    
    Final Array values
    707 606 505 404 303 202 101
    

    Para bash mais antigo, você precisa usar um loop (no bash (desde 2.04)) e usar $apara evitar o espaço à direita:

    #!/bin/bash
    
    array=(101 202 303 404 505 606 707)
    last=${#array[@]}
    
    a=""
    for (( i=last-1 ; i>=0 ; i-- ));do
        printf '%s%s' "$a" "${array[i]}"
        a=" "
    done
    echo
    

    Para bash desde 2.03:

    #!/bin/bash
    array=(101 202 303 404 505 606 707)
    last=${#array[@]}
    
    a="";i=0
    while [[ last -ge $((i+=1)) ]]; do 
        printf '%s%s' "$a" "${array[ last-i ]}"
        a=" "
    done
    echo
    

    Além disso (usando o operador de negação bit a bit) (desde o bash 4.2+):

    #!/bin/bash
    array=(101 202 303 404 505 606 707)
    last=${#array[@]}
    
    a=""
    for (( i=0 ; i<last ; i++ )); do 
        printf '%s%s' "$a" "${array[~i]}"
        a=" "
    done
    echo
    
    • 10
  6. user23013
    2017-12-28T08:09:09+08:002017-12-28T08:09:09+08:00

    Feio, impossível de manter, mas uma linha:

    eval eval echo "'\"\${array['{$((${#array[@]}-1))..0}']}\"'"
    
    • 6
  7. Stéphane Chazelas
    2018-09-10T12:40:44+08:002018-09-10T12:40:44+08:00

    Para inverter uma matriz arbitrária (que pode conter qualquer número de elementos com quaisquer valores):

    Com zsh:

    array_reversed=("${(@Oa)array}")
    

    Com bash4.4+, dado que bashas variáveis ​​não podem conter bytes NUL de qualquer maneira, você pode usar GNU tac -s ''nos elementos impressos como registros delimitados por NUL:

    readarray -td '' array_reversed < <(
      ((${#array[@]})) && printf '%s\0' "${array[@]}" | tac -s '')
    

    Observe, no entanto, que os arrays bash foram inspirados em arrays ksh em vez de arrays csh/zsh e são mais como arrays associativos com chaves limitadas a inteiros positivos (os chamados arrays esparsos ), e esse método não preserva as chaves dos arrays. Por exemplo, para qualquer array como:

    array=( [3]=a [12]=b [42]=c )
    

    você consegue

    array_reversed=( [0]=c [1]=b [2]=a )
    

    POSIXly, para inverter a única matriz de shell POSIX ( $@, made of $1, $2...) no lugar:

    code='set --'
    n=$#
    while [ "$n" -gt 0 ]; do
      code="$code \"\${$n}\""
      n=$((n - 1))
    done
    eval "$code"
    
    • 4
  8. Paul Hodges
    2019-07-03T09:51:24+08:002019-07-03T09:51:24+08:00

    Solução bash pura, funcionaria como uma linha única.

    $: for (( i=${#array[@]}-1; i>=0; i-- ))
    >  do rev[${#rev[@]}]=${array[i]}
    >  done
    $: echo  "${rev[@]}"
    7 6 5 4 3 2 1
    
    • 4
  9. George Vasiliou
    2017-12-27T14:14:34+08:002017-12-27T14:14:34+08:00

    Embora eu não vá contar algo novo e também usarei tacpara inverter o array, acho que vale a pena mencionar abaixo a solução de linha única usando o bash versão 4.4:

    $ read -d'\n' -a array < <(printf '%s\n' "${array[@]}" |tac)
    

    Teste:

    $ array=(1 2 3 4 5 6 10 11 12)
    $ echo "${array[@]}"
    1 2 3 4 5 6 10 11 12
    $ read -d'\n' -a array < <(printf '%s\n' "${array[@]}"|tac)
    $ echo "${array[@]}"
    12 11 10 6 5 4 3 2 1
    

    Lembre-se de que o nome da var dentro de read é o nome da matriz original, portanto, nenhuma matriz auxiliar é necessária para armazenamento temporário.

    Implementação alternativa ajustando o IFS:

    $ IFS=$'\n' read -d '' -a array < <(printf '%s\n' "${array[@]}"|tac);declare -p array
    declare -a array=([0]="12" [1]="11" [2]="10" [3]="6" [4]="5" [5]="4" [6]="3" [7]="2" [8]="1")
    

    PS: Acho que as soluções acima não funcionarão na bashversão abaixo 4.4devido à readimplementação diferente da função interna do bash.

    • 2
  10. Viet Anh Duong
    2021-06-23T00:30:48+08:002021-06-23T00:30:48+08:00

    Tente isso

    #!/bin/bash
    
    array=(1 2 3 4 5 6)
    index=$((${#array[@]}-1))
    
    for e in "${array[@]}"; do
      result[$((index--))]="$e"
    done
    
    echo "${result[@]}"
    
    
    • 1

relate perguntas

  • Problema estranho ao passar variáveis ​​do arquivo de texto

  • Enquanto a linha lê mantendo os espaços de escape?

  • MySQL Select com função IN () com array bash

  • ordem de substituição de processos `te` e `bash`

  • Execute um script muito lento até que seja bem-sucedido

Sidebar

Stats

  • Perguntas 205573
  • respostas 270741
  • best respostas 135370
  • utilizador 68524
  • Highest score
  • respostas
  • Marko Smith

    Matriz JSON para bash variáveis ​​usando jq

    • 4 respostas
  • Marko Smith

    A data pode formatar a hora atual para o fuso horário GMT? [duplicado]

    • 2 respostas
  • Marko Smith

    bash + lê variáveis ​​e valores do arquivo pelo script bash

    • 4 respostas
  • Marko Smith

    Como posso copiar um diretório e renomeá-lo no mesmo comando?

    • 4 respostas
  • Marko Smith

    conexão ssh. Conexão X11 rejeitada devido a autenticação incorreta

    • 3 respostas
  • Marko Smith

    Como baixar o pacote não instalá-lo com o comando apt-get?

    • 7 respostas
  • Marko Smith

    comando systemctl não funciona no RHEL 6

    • 3 respostas
  • Marko Smith

    rsync porta 22 e 873 uso

    • 2 respostas
  • Marko Smith

    snap /dev/loop em 100% de utilização -- sem espaço livre

    • 1 respostas
  • Marko Smith

    chave de impressão jq e valor para todos no subobjeto

    • 2 respostas
  • Martin Hope
    EHerman Matriz JSON para bash variáveis ​​usando jq 2017-12-31 14:50:58 +0800 CST
  • Martin Hope
    Christos Baziotis Substitua a string em um arquivo de texto enorme (70 GB), uma linha 2017-12-30 06:58:33 +0800 CST
  • Martin Hope
    Drux A data pode formatar a hora atual para o fuso horário GMT? [duplicado] 2017-12-26 11:35:07 +0800 CST
  • Martin Hope
    AllisonC Como posso copiar um diretório e renomeá-lo no mesmo comando? 2017-12-22 05:28:06 +0800 CST
  • Martin Hope
    Steve Como as permissões de arquivo funcionam para o usuário "root"? 2017-12-22 02:46:01 +0800 CST
  • Martin Hope
    Bagas Sanjaya Por que o Linux usa LF como caractere de nova linha? 2017-12-20 05:48:21 +0800 CST
  • Martin Hope
    Cbhihe Altere o editor padrão para vim para _ sudo systemctl edit [unit-file] _ 2017-12-03 10:11:38 +0800 CST
  • Martin Hope
    showkey Como baixar o pacote não instalá-lo com o comando apt-get? 2017-12-03 02:15:02 +0800 CST
  • Martin Hope
    youxiao Por que os diretórios /home, /usr, /var, etc. têm o mesmo número de inode (2)? 2017-12-02 05:33:41 +0800 CST
  • Martin Hope
    user223600 gpg — o comando list-keys gera uid [ desconhecido ] depois de importar a chave privada para uma instalação limpa 2017-11-26 18:26:02 +0800 CST

Hot tag

linux bash debian shell-script text-processing ubuntu centos shell awk ssh

Explore

  • Início
  • Perguntas
    • Recentes
    • Highest score
  • tag
  • help

Footer

AskOverflow.Dev

About Us

  • About Us
  • Contact Us

Legal Stuff

  • Privacy Policy

Language

  • Pt
  • Server
  • Unix

© 2023 AskOverflow.DEV All Rights Reserve