web-dev-qa-db-fra.com

Tableaux associatifs Bash 4: erreur "declare: -A: option invalide"

J'ai écrit un script qui utilise des tableaux associatifs dans bash (v 4).

Cela fonctionne très bien sur ma machine locale qui utilise 4.1.5(1)-release.

Sur la machine de production, en utilisant 4.1.0(1)-release la ligne suivante, qui déclare le tableau assoc, échoue:

declare -A uniqjars

avec le message:

/script.sh: line 11: declare: -A: invalid option
declare: usage: declare [-afFirtx] [-p] [name[=value] ...]

J'avais l'impression que c'était une fonction générale de bash 4?

Dans l'homme pour bash sur la machine de production, il discute de l'utilisation de -A donc je suppose que devrait fonctionner.

Les tableaux associatifs sont créés à l'aide de declare -A name.

Je peux confirmer que le script utilise la bonne version de bash en imprimant la valeur de echo 'bash -version.

Que pourrais-je faire de mal?

49
Joel

Assurez-vous que la version de bash est invoquée en tant qu'interpréteur en haut de votre script Shell (#!/bin/bash ou autre) est également la version 4. Si vous faites:

bash --version

et ça vous donne la v4, faites un which bash pour vérifier son emplacement.

34
Richard H

Voici une solution de contournement, si vous souhaitez utiliser des caractères comme index de tableau avec bash v3:

array=(
    'hello::world.'
    'Nice::to meet you'
)

for index in "${array[@]}" ; do
    KEY="${index%%::*}"
    VALUE="${index##*::}"
    echo "$KEY - $VALUE"
done

Production:

hello - world.
Nice - to meet you
28
meigrafd

Ce qui suit semble être un scénario typique sur macOS après l'installation d'un nouveau Bash avec Homebrew:

  • /bin/bash est l'ancien Bash, 3.2
  • /usr/local/bin/bash est le nouveau Bash qui connaît les tableaux associatifs (4.0 ou plus récent)
  • type bash pointe vers /usr/local/bin/bash et bash --version est le nouveau (car il se résout en /usr/local/bin/bash --version)

Cependant, les scripts avec un #!/bin/bash Ligne Shebang exécutée avec ./script utilisera l'ancien Bash (le scénario de la question). Les solutions sont:

  • Appelez le script avec bash script: le nouveau Bash sera utilisé. Inconvénient: vous devez toujours l'appeler comme ça.
  • Modifiez la ligne Shebang en #!/usr/local/bin/bash. Inconvénient: sur de nombreux systèmes, il n'y a pas de Bash dans /usr/local/bin et votre script n'est plus portable.
  • Modifiez la ligne Shebang en #!/usr/bin/env bash. Ceci utilisera le premier bash dans votre PATH, qui devrait être le nouveau. C'est assez portable; le seul inconvénient est que vous ne savez pas exactement quel Bash sera exécuté.

Voir aussi ces Q&R:

18
Benjamin W.
  1. Vérifiez le shell actuel que vous utilisez avec cette cmd:

    echo $Shell
    

    Par exemple. cela pourrait dire /bin/bash

  2. Exécutez --version Sur ce $Shell:

    /bin/bash --version
    

    Il peut produire quelque chose comme GNU bash, version 3.2.57(1)-release (x86_64-Apple-darwin16)

    Si c'est avant la version 4, vous devrez mettre à niveau.

  3. Vérifiez si vous disposez déjà d'un shell bash avec la version 4. Essayez d'exécuter:

    bash --version
    

    Si c'est le cas, il vous suffit de changer votre Shell par défaut en ce Shell.

    Vous pouvez utiliser ces cmds pour ce faire:

    Sudo bash -c 'echo /usr/local/bin/bash >> /etc/shells'
    Sudo chsh -s /usr/local/bin/bash
    

    Le premier ajoute le Shell aux shells autorisés. Le second change en fait votre Shell par défaut.

8
Tyler

Voici comment obtenir la version bash mise à jour sur OS X, vous devez installer brew puis bash.

$ /bin/bash --version    
GNU bash, version 3.2.57(1)-release (x86_64-Apple-darwin14)

$ brew install bash    
... install

$ /usr/local/bin/bash --version    
GNU bash, version 4.3.46(1)-release (x86_64-Apple-darwin14.5.0)
7
khancell

meigrafd la réponse a résolu mon problème, donc si vous utilisez un Shebang incorrect ou encore sur la version 3 de bash, ce qui suit me permet de renvoyer une valeur basée sur sa clé associée:

array=(
    'hello::world.'
    'Nice::to meet you'
)

for index in "${array[@]}" ; do
  KEY="${index%%::*}"
  VALUE="${index##*::}"
  if [ "$KEY" == "Nice" ]; then
    echo "$VALUE"
    break
  fi
done

Cela renverra la valeur "pour vous rencontrer".

6
KeithJ

Rien ci-dessus ne m'a aidé, j'ai donc ouvert/etc/shells et changé la ligne - /bin/bash à /usr/local/bin/bash, puis l'a rechargée avec source /etc/shells et maintenant je peux profiter de nouvelles possibilités de v4 de bash

3
Mihey Mik

L'ancienne version BASH ne supportait pas declare -A syntaxe de déclaration des tableaux. Je suggère d'utiliser l'un de ces 2 formulaires pour déclarer des tableaux en bash afin de le rendre compatible avec l'ancienne version bash de votre système de production:

arr=( '10' '20' '30' )
echo ${arr[@]}

ou

arr[0]=10
arr[1]=20
arr[2]=30
echo ${arr[@]}
2
anubhava

Par la commande:

help declare
declare: declare [-aAfFgilnrtux] [-p] [name[=value] ...]
  Set variable values and attributes.

Declare variables and give them attributes.  If no NAMEs are given,
display the attributes and values of all variables.
Options which are set attributes:
  -a        to make NAMEs indexed arrays (if supported)
  -A        to make NAMEs associative arrays (if supported)

Notez que "-a" en minuscule et "-A" en majuscule sont "(si pris en charge)". Aussi, si vous regardez le message d'erreur affiché pour déclarer l'utilisation:

/script.sh: line 11: declare: -A: invalid option
declare: usage: declare [-afFirtx] [-p] [name[=value] ...]

Les options données sont "[-afFirtx]" montrant l'utilisation d'un "-a" en minuscule mais pas d'un "-A" en majuscule. Comparez cela à la chaîne d'utilisation de la commande help. Il semble que ce ne soit tout simplement pas pris en charge sur la machine donnée.

1
EnterUserNameHere

Essayez d'utiliser un Shebang différent. Sur mon Mac:

$ which bash
/usr/local/bin/bash

Donc, ce script fonctionne bien, produisant "Hello World":

#!/usr/local/bin/bash
declare -A assoc
assoc[hello]="Hello World"
echo ${assoc[hello]}
0
Khanan