Lendo uma string delimitada em uma matriz no Bash


206

Eu tenho uma variável que contém uma seqüência de caracteres delimitada por espaço:

line="1 1.50 string"

Quero dividir essa seqüência de caracteres com espaço como delimitador e armazenar o resultado em uma matriz, para que o seguinte:

echo ${arr[0]}
echo ${arr[1]}
echo ${arr[2]}

saídas

1
1.50
string

Em algum lugar, encontrei uma solução que não funciona:

arr=$(echo ${line})

Se eu executar as instruções de eco acima depois disso, recebo:

1 1.50 string
[empty line]
[empty line]

Eu também tentei

IFS=" "
arr=$(echo ${line})

com o mesmo resultado. Alguém pode ajudar por favor?


Veja esta resposta no Unix e Linux Stack Exchange: Usando sed com herestring (<<<) e leia -a . set -f; arr=($string); set +fparece ser mais rápido que read -r -a <<< $string.
codeforester

Respostas:


331

Para converter uma string em uma matriz, use

arr=($line)

ou

read -a arr <<< $line

É crucial não usar aspas, pois isso funciona.


7
e para fazer uma verificação de sanidade de sua bela nova matriz:for i in ${arr[@]}; do echo $i; done
Banjer

5
ou apenasecho ${arr[@]}
Banjer

13
Ambas as formas podem falhar se $linehouver caracteres brilhantes. mkdir x && cd x && touch A B C && line="*" arr=($line); echo ${#arr[@]}dá 3
Tino

3
declare -a "arr=($line)"irá ignorar IFSdelimitadores dentro de strings entre aspas
Dave

4
@Tino No. When line='*' , read -a arr <<<$linesempre funciona, mas apenas arr=($line)falha.
Johnny Wong


34

In: arr=( $line ). A "divisão" vem associada a "glob".
Os caracteres universais ( *, ?e[] ) serão expandidos para nomes de arquivos correspondentes.

A solução correta é apenas um pouco mais complexa:

IFS=' ' read -a arr <<< "$line"

Nenhum problema de globbing; o caractere de divisão é definido $IFS, variáveis ​​citadas.


5
Essa deve ser a resposta aceita. A afirmação arr=($line)na resposta aceita sofre de problemas de globbing. Por exemplo, tente: line="twinkling *"; arr=($line); declare -p arr.
codeforester

A citação é opcional para herestring, <<<mas pode ser uma boa ideia ainda usar aspas duplas para garantir consistência e legibilidade.
codeforester

7

Se você precisar de expansão de parâmetro, tente:

eval "arr=($line)"

Por exemplo, pegue o seguinte código.

line='a b "c d" "*" *'
eval "arr=($line)"
for s in "${arr[@]}"; do 
    echo "$s"
done

Se o diretório atual contendo os arquivos a.txt, b.txte c.txt, em seguida, executar o código deve produzir a seguinte saída.

a
b
c d
*
a.txt
b.txt
c.txt

-9
line="1 1.50 string"

arr=$( $line | tr " " "\n")

for x in $arr
do
echo "> [$x]"
done

O looping é errado, ele divide a matriz fina e o tubo na tré supérfluo, mas ele deve varrer "${arr[@]}"vez, não$arr
Zorf
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.