752 votes

Comment définir des tables de hachage en bash ?

Tout ce que dit titre. Je suis surpris par l’insuffisance des résultats de recherche Google pour cette question ! Ce que je veux est l’équivalent de dictionnaires Python mais en bash (et par conséquent, devrait fonctionner sur OSX, Ubuntu et autres distributions majeures de Linux).

1265voto

lhunath Points 27045

Bash 4

Bash 4 prend en charge cette fonctionnalité. Assurez-vous que votre script hashbang est - #!/usr/bin/env bash ou #!/bin/bash ou quoi que ce soit d'autre que des références bash et pas sh. Assurez-vous que vous êtes l'exécution de votre script, et ne pas faire quelque chose de stupide comme sh script qui serait la cause de votre bash hashbang pour être ignoré. C'est des trucs de base, mais autant garder à défaut, d'où la ré-itération.

Vous déclarez un tableau associatif en faisant:

declare -A animals

Vous pouvez le remplir avec des éléments à l'aide du tableau normal opérateur d'affectation:

animals=( ["moo"]="cow" ["woof"]="dog")

Ou les fusionner:

declare -A animals=( ["moo"]="cow" ["woof"]="dog")

Ensuite les utiliser comme des tableaux normaux. "${animals[@]}" développe les valeurs, "${!animals[@]}" (avis de l' !) élargit les touches. N'oubliez pas de les citer:

echo "${animals["moo"]}"
for sound in "${!animals[@]}"; do echo "$sound - ${animals["$sound"]}"; done

Bash 3

Avant de bash 4, vous n'avez pas de tableaux associatifs. Ne pas utiliser eval à les imiter. Vous devez éviter eval comme la peste, parce que c' est la peste de la création de scripts shell. La raison la plus importante est que vous ne voulez pas traiter vos données sous forme de code (il y en a beaucoup d'autres raisons aussi).

D'abord et avant tout: il suffit de considérer la mise à niveau vers bash 4. Sérieusement. L'avenir est maintenant, arrêtez de vivre dans le passé et qui en souffrent en forçant stupide cassé et laid hacks sur votre code et chaque pauvre âme coincé à l'entretenir.

Si vous avez quelques stupide excuse pourquoi vous "ne pouvez pas mettre à niveau", declare est de loin la meilleure option. Il n'a pas d'évaluer les données que bash code comme celui - eval , et comme tel, il ne pas permettre à un code arbitraire de l'injection assez facilement.

Nous allons préparer la réponse en introduisant les concepts:

Tout d'abord, l'indirection (sérieusement, n'utilisez jamais de cela, sauf si vous êtes des malades mentaux ou qui ont une autre mauvaise excuse pour l'écriture de hacks).

$ animals_moo=cow; sound=moo; i="animals_$sound"; echo "${!i}"
cow

Deuxièmement, declare:

$ sound=moo; animal=cow; declare "animals_$sound=$animal"; echo "$animals_moo"
cow

Les réunir:

# Set a value:
declare "array_$index=$value"

# Get a value:
arrayGet() { 
    local array=$1 index=$2
    local i="${array}_$index"
    printf '%s' "${!i}"
}

Nous allons utiliser:

$ sound=moo
$ animal=cow
$ declare "animals_$sound=$animal"
$ arrayGet animals "$sound"
cow

Remarque: declare ne peut pas être mis en fonction. Toute utilisation de l' declare à l'intérieur d'un bash fonction transforme la variable elle crée des locaux à la portée de cette fonction, ce qui signifie que nous ne pouvons pas accéder ou de modifier les tableaux globaux. (En bash 4 vous pouvez utiliser déclarer g de déclarer des variables globales - mais en bash 4, vous devriez être en utilisant des tableaux associatifs en premier lieu, non pas ce hack.)

Résumé

La mise à niveau vers bash 4 et utiliser declare -A. Si vous ne pouvez pas, envisager de passer entièrement à l' awk avant de faire laid hacks comme décrit ci-dessus. Et certainement rester le diable loin de eval hackery.

149voto

Bubnoff Points 1236

Il y a substitution de paramètres, si elle peut être un PC aussi bien.. .comme indirection.

Le BASH 4 voies est mieux, bien sûr, mais si vous avez besoin d’un hack.. .seuls va faire un hack. Vous pouvez rechercher le tableau/hash avec des techniques similaires.

117voto

aktivb Points 387

C’est ce que je cherchais ici :

Cela n’a pas fonctionné pour moi avec bash 4.1.5 :

30voto

Al P. Points 337

Vous pouvez encore modifier les hput()/hget() de l'interface de sorte que vous avez nommé les hachages comme suit:

hput() {
    eval "$1""$2"='$3'
}

hget() {
    eval echo '${'"$1$2"'#hash}'
}

et puis

hput capitals France Paris
hput capitals Netherlands Amsterdam
hput capitals Spain Madrid
echo `hget capitals France` and `hget capitals Netherlands` and `hget capitals Spain`

Cela vous permet de définir d'autres cartes qui ne sont pas en conflit (par exemple, 'rcapitals" qui n'pays recherche par ville capitale). Mais, de toute façon, je pense que vous trouverez que c'est assez terrible, en terme de performance.

Si vous voulez vraiment rapide hachage de recherche, il y a un terrible, terrible hack qui fonctionne vraiment bien. C'est cela: écrire vos clés/valeurs dans un fichier temporaire, un par ligne, puis utiliser " grep "^$touche" " pour les faire sortir à l'aide de tubes à couper ou awk ou sed ou que ce soit pour récupérer les valeurs.

Comme je l'ai dit, il a l'air terrible, et il semble que ça devrait être lente et de faire toutes sortes de inutiles IO, mais dans la pratique, il est très rapide (cache disque est génial, n'est-ce pas?), même pour les très grandes tables de hachage. Vous devez appliquer la clé de l'unicité de vous-même, etc. Même si vous n'avez que quelques centaines d'entrées, le fichier de sortie/grep combo va être un peu plus rapide - en mon expérience plusieurs fois plus rapide. Elle consomme également moins de mémoire.

Voici une façon de le faire:

hinit() {
    rm -f /tmp/hashmap.$1
}

hput() {
    echo "$2 $3" >> /tmp/hashmap.$1
}

hget() {
    grep "^$2 " /tmp/hashmap.$1 | awk '{ print $2 };'
}

hinit capitals
hput capitals France Paris
hput capitals Netherlands Amsterdam
hput capitals Spain Madrid

echo `hget capitals France` and `hget capitals Netherlands` and `hget capitals Spain`

19voto

DigitalRoss Points 80400
<pre><code></code><p><hr><pre><code></code></pre></pre>

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X