O que exatamente é o comprimento de uma matriz no bash e como diferem '*' e '@'?

0

Eu tenho o seguinte script de exemplo e quero saber o que exatamente é o comprimento de uma matriz, são esses bytes, caracteres ou o que mais?

#!/bin/bash

# Arrays
# @ vs. *

ape=( "Apple Banana" "Emacs Window" "Panda Bamboo Nature" )
cape=( 'Ping Pong' 'King Kong' 'King Fisher Club' 'Blurb' )
jade=( ally belly cally delly )

echo Expansion with \*
echo ${ape[*]}
echo ${cape[*]}
echo -e "${jade[*]}\n"

echo Expansion with \@
echo ${ape[@]}
echo ${cape[*]}
echo -e "${jade[@]}\n"

echo Elements with \*
echo ${#ape[*]}
echo ${#cape[*]}
echo ${#jade[*]}

echo Elements with \@
echo ${#ape[@]}
echo ${#cape[@]}
echo ${#jade[*]}

echo -e "\nLength"
echo ${#ape}
echo ${#cape}
echo ${#jade}

Nas páginas do manual, sei que a expansão da matriz difere de * para @ se a palavra tiver aspas duplas ou não, mas não vejo nenhuma diferença. Por que eu tenho em ambos os casos os mesmos resultados?

A saída é a seguinte:

Expansion with *
Apple Banana Emacs Window Panda Bamboo Nature
Ping Pong King Kong King Fisher Club Blurb
ally belly cally delly

Expansion with @
Apple Banana Emacs Window Panda Bamboo Nature
Ping Pong King Kong King Fisher Club Blurb
ally belly cally delly

Elements with *
3
4
4
Elements with @
3
4
4

Length
12
9
4
    
por John Goofy 13.03.2018 / 16:42

2 respostas

4

Você perdeu o caso em que ele mostra que * expandirá a matriz para uma única string e @ expandirá para strings citadas individualmente:

printf 'string "%s"\n' "${cape[*]}"

que gera

string "Ping Pong King Kong King Fisher Club Blurb"

e

printf 'string "%s"\n' "${cape[@]}"

que gera

string "Ping Pong"
string "King Kong"
string "King Fisher Club"
string "Blurb"

Lembre-se que echo apenas concatena seus argumentos e os imprime, enquanto printf preencherá sua string de formato com os argumentos e repetirá o mesmo formato se mais argumentos forem fornecidos.

Além disso,

for s in "${cape[*]}"; do
    echo "$s"
done

gera uma única linha de saída, enquanto

for s in "${cape[@]}"; do
    echo "$s"
done

gera um por elemento de matriz.

Sempre deseje usar aspas duplas em torno das expansões ${array[*]} e ${array[@]} , a menos que você queira, por algum motivo, invocar explicitamente a divisão de palavras e a globulação de nomes de arquivos. E você usa * ou @ dependendo se você precisa dos elementos da matriz todos juntos como uma string, ou citados individualmente.

Na minha experiência, raramente se usa [*] .

Ao obter o tamanho de uma matriz, não importa qual * ou @ você usa. Mas se você não usar nenhum, você obterá o tamanho do primeiro elemento do array.

    
por 13.03.2018 / 16:51
0

Com base nas diferentes citações usadas nas atribuições de variáveis, acredito que você tenha interpretado erroneamente a frase "se a palavra tiver aspas duplas ou não" para significar "se os elementos da matriz tiverem aspas duplas", enquanto o manual pretende "se a palavra que representa a variável que está sendo expandida tiver aspas duplas ou não".

Você também está usando echo com as expansões variáveis acontecendo na mesma linha; você pode obter resultados mais claros se usar algo mais configurável, como printf (como Kusalananda ), ou como:

$ printf -- '->%s<-\n' "${ape[@]}"
->Apple Banana<-
->Emacs Window<-
->Panda Bamboo Nature<-

Se você pudesse ver os valores intermediários que printf faz, você veria:

printf -- '->%s<-\n' "Apple Banana" "Emacs Window" "Panda Bamboo Nature"

Em oposição à versão sem aspas:

$ printf -- '->%s<-\n' ${ape[@]}
->Apple<-
->Banana<-
->Emacs<-
->Window<-
->Panda<-
->Bamboo<-
->Nature<-

... onde os valores intermediários são:

printf -- '->%s<-\n' Apple Banana Emacs Window Panda Bamboo Nature

... que mostra exatamente para o que os elementos foram expandidos. No primeiro caso, a variável é citada, portanto, nenhuma divisão adicional de palavras acontece e você obtém os três elementos de volta. No segundo caso, cada um desses três elementos também passa pela divisão de palavras, então printf sete elementos para imprimir.

O "comprimento" de uma matriz é geralmente o número de elementos que você gerou com a sintaxe ${#ape[@]} . Usando ${#ape} , pergunta o comprimento do primeiro elemento:

Referencing an array variable without a subscript is equivalent to referencing with a subscript of 0

e é por isso que você obtém esses valores diferentes.

    
por 13.03.2018 / 16:59

Tags