Préface: J'aime Bash et n'ai pas l'intention de commencer une sorte d'argumentation ni de guerre sainte, et j'espère que ce n'est pas une question extrêmement naïve.
Cette question est quelque peu liée à ce post sur superutilisateur, mais je ne pense pas que l'OP savait vraiment ce qu'il demandait. J'utilise Bash sur FreeBSD, Linux, OS X et Cygwin sous Windows. J'ai également eu une vaste expérience récemment avec PowerShell sur Windows.
Existe-t-il une coquille pour * Nix, déjà disponible ou dans les travaux compatibles avec Bash mais ajoute une couche de script orientée objet dans le mélange? La seule chose que je connaisse de celui qui se rapproche est la console python, mais aussi loin que je peux le dire, cela ne donne pas accès à l'environnement Standard Shell. Par exemple, je ne peux pas que cd ~
Et ls
, alors chmod +x file
À l'intérieur de la console python. Je devrais utiliser python pour effectuer ces tâches plutôt que les fichiers binaires UNIX standard, ou appeler les fichiers binaires en utilisant le code python.
Un tel shell existe-t-il?
Je peux penser à trois caractéristiques souhaitables dans une coquille:
Les coques UNIX ont tendance à se concentrer sur l'aspect interactif et à sous-traiter la plupart de l'accès au système et à une partie de la programmation à des outils externes, tels que:
ftp
pour ftpmail
, Mail
, mailx
, etc. pour un courrier électronique de basecron
pour des tâches planifiéesdbus-*
ou qdbus ) Pour diverses informations système et des tâches de configuration (y compris les environnements de bureau modernes tels que KDE ≥4)Beaucoup, beaucoup de choses peuvent être faites en invoquant une commande avec les bons arguments ou l'entrée de la pipi. C'est une approche très puissante - mieux avoir un outil par tâche qui le fait bien qu'un seul programme qui fait tout ce qui est mal, mais il a ses limites.
Une limite majeure des coquilles UNIX, et je soupçonne que c'est ce que vous êtes après avec votre exigence "Script de script orientée objet", c'est qu'ils ne sont pas bons pour retenir des informations d'une commande à la suivante ou combinant des commandes de manière plus amicale que un pipeline. En particulier, la communication inter-programme est basée sur le texte. Les applications ne peuvent être combinées que si elles sérialisent leurs données de manière compatible. C'est à la fois une bénédiction et une malédiction: l'approche TOUT-IS-TEXT permet de réaliser rapidement des tâches simples, mais augmente la barrière pour des tâches plus complexes.
La convivialité interactive fonctionne également plutôt contre la maintenabilité du programme. Les programmes interactifs doivent être courts, nécessiter peu de citations, ne vous dérangez pas avec des déclarations variables ou de taper, etc. Les programmes de maintenance doivent être lisibles (afin de ne pas avoir de nombreuses abréviations), devraient être lisibles (afin que vous n'ayez pas à vous demander si un mot nu Une chaîne, un nom de fonction, un nom de variable, etc.) doit avoir des contrôles de cohérence telles que des déclarations variables et la dactylographie, etc.
En résumé, une coquille est un compromis difficile à atteindre. OK, cela met fin à la section de la discordance, sur les exemples.
Le coquille PERL (PSH) "Combine la nature interactive d'une coquille UNIX avec la puissance de Perl". Des commandes simples (même des pipelines) peuvent être entrées dans la syntaxe Shell; Tout le reste est Perl. Le projet n'a pas été en développement depuis longtemps. C'est utilisable, mais n'a pas atteint le point où j'envisagerais de l'utiliser sur Purl Perl (pour script) ou une coque pure (de manière interactive ou de script).
ipython est une amélioration interactive Python console, particulièrement ciblée au calcul numérique et parallèle. C'est un projet relativement jeune. Il s'agit d'un projet relativement jeune.
IRB (Ruby interactif) est le Ruby équivalent de la Python Console.
SCSH est une implémentation de schéma (c'est-à-dire un langage de programmation décent) avec le type de fixations de système traditionnellement trouvées dans des coquilles UNIX (chaînes, processus, fichiers). Cela ne vise pas à être utilisable comme une coque interactive cependant.
ZSH est une coque interactive améliorée. Son point fort est l'interactivité (édition de ligne de commande, achèvement, tâches communes accomplies avec la syntaxe TERSE mais cryptique). Ses caractéristiques de programmation ne sont pas si grandes (à égalité avec ksh), mais il est livré avec un certain nombre de bibliothèques pour le contrôle des terminaux, les regexps, la mise en réseau, etc.
poisson est un début propre sur une coque de style UNIX. Il n'a pas de meilleure programmation ni de meilleures fonctionnalités d'accès au système. Parce qu'il brise la compatibilité avec SH, il a plus de place pour évoluer de meilleures fonctionnalités, mais cela n'est pas arrivé.
Addendum: Une autre partie de la boîte à outils UNIX traite de nombreuses choses comme fichiers:
/sys
fournit plus de matériel et de contrôle du système./proc
système de fichiers.Peut-être que l'avenir des coquilles UNIX n'est peut-être pas meilleur accès au système via des commandes (et de meilleures structures de contrôle pour combiner les commandes) mais un meilleur accès du système via des systèmes de fichiers (qui se combinent quelque peu différemment - je ne pense pas que nous avons élaboré ce que nous avons élaboré ce que l'idiome clé (comme le tuyau d'obus) reste).
Vous n'avez pas besoin de beaucoup de code Bash pour mettre en œuvre des cours ou des objets à bash.
Dis, 100 lignes.
Bash a des tableaux associatifs qui peuvent être utilisés pour mettre en œuvre un système d'objet simple avec héritage, méthodes et propriétés.
Donc, vous pourriez définir une classe comme celle-ci:
class Queue N=10 add=q_add remove=q_remove
Créer une instance de cette file d'attente pourrait être faite comme ceci:
class Q:Queue N=100
ou
inst Q:Queue N=100
Étant donné que les classes sont implémentées avec un tableau, classe et INST sont vraiment synonymes - une sorte de comme dans JavaScript.
Ajout d'articles dans cette file d'attente pourrait être fait comme ceci:
$Q add 1 2 aaa bbb "a string"
Supprimer des éléments dans une variable x pourrait être fait comme ceci:
$Q remove X
Et la structure de dumping d'un objet pourrait être faite comme ceci:
$Q dump
Qui reviendrait quelque chose comme ça:
Q {
parent=Queue {
parent=ROOT {
this=ROOT
0=dispatch ROOT
}
class=Queue
N=10
add=q_add
remove=q_remove
0=dispatch Queue
}
class=Q
N=4
add=q_add
remove=q_remove
0=dispatch Q
1=
2=ccc ddd
3=
4=
}
Les classes sont créées à l'aide d'une fonction de classe comme celle-ci:
class(){
local _name="$1:" # append a : to handle case of class with no parent
printf "$FUNCNAME: %s\n" $_name
local _this _parent _p _key _val _members
_this=${_name%%:*} # get class name
_parent=${_name#*:} # get parent class name
_parent=${_parent/:/} # remove handy :
declare -g -A $_this # make class storage
[[ -n $_parent ]] && { # copy parent class members into this class
eval _members=\"\${!$_parent[*]}\" # get indices of members
for _key in $_members; do # inherit members from parent
eval _val=\"\${$_parent[$_key]}\" # get parent value
eval $_this[$_key]=\"$_val\" # set this member
done
}
shift 1
# overwrite with specific values for this object
ROOT_set $_this "$@" "0=dispatch $_this" "parent=${_parent:-ROOT}" "class=$_this"
}
Remarque: lorsque vous définissez une nouvelle classe ou une nouvelle instance, vous pouvez remplacer n'importe quelle valeur ou fonction de membre.
Les matrices associatives Bash ont une bizarrerie qui rend ce travail soigneusement: $ q [0]} est identique à $ q. Cela signifie que nous pouvons utiliser le nom de la matrice pour appeler une fonction d'expédition de méthode:
dispatch(){
local _this=$1 _method=$2 _fn
shift 2
_fn="$_this[$_method]" # reference to method name
${!_fn} $_this "$@"
}
Un face en bas est que je ne peux pas utiliser [0] pour les données afin que mes files d'attente (dans ce cas) démarrent de l'index = 1. Sinon, j'aurais pu utiliser des indices associatifs comme "Q + 0".
Pour obtenez et SET membres Vous pouvez faire quelque chose comme ceci:
# basic set and get for key-value members
ROOT_set(){ # $QOBJ set key=value
local _this=$1 _exp _key _val
shift
for _exp in "$@"; do
_key=${_exp%%=*}
_val="${_exp#*=}"
eval $_this[$_key]=\"$_val\"
done
}
ROOT_get(){ # $QOBJ get var=key
local _this=$1 _exp _var _key
shift
for _exp in "$@"; do
_var=${_exp%%=*}
_key=${_exp#*=}
eval $_var=\"\${$_this[$_key]}\"
done
}
Et à Dump une structure d'objet, j'ai fait ceci:
Remarque: Ceci n'est pas requis pour OOP à bash, mais il est agréable de voir comment les objets sont fabriqués.
# dump any object
obj_dump(){ # obj_dump <object/class name>
local _this=$1 _j _val _key; local -i _tab=${2:-(${#_this}+2)} # add 2 for " {"
_tab+=2 # hanging indent from {
printf "%s {\n" $_this
eval "_key=\"\${!$_this[*]}\""
for _j in $_key; do # print all members
eval "_val=\"\${$_this[\$_j]}\""
case $_j in
# special treatment for parent
parent) printf "%*s%s=" $_tab "" $_j; ${!_val} dump $(( _tab+${#_j}+${#_val}+2 ));;
*) printf "%*s%s=%s\n" $_tab "" $_j "$_val";;
esac
done
(( _tab-=2 ))
printf "%*s}\n" $_tab ""
return 0
}
Mon OOP conception n'a pas considéré d'objets dans des objets - à l'exception de la classe héritée. Vous pouvez les créer séparément ou créer un constructeur spécial comme classe (). * Obj_dump * devrait être modifié pour détecter classes internes pour les imprimer récursives.
Oh! et je définis manuellement une classe racine pour simplifier classe Fonction:
declare -gA ROOT=( \
[this]=ROOT \
[0]="dispatch ROOT" \
[dump]=obj_dump \
[set]="ROOT_set" \
[get]="ROOT_get" \
)
Avec quelques fonctions de la file d'attente, j'ai défini certaines classes comme celle-ci:
class Queue \
in=0 out=0 N=10 \
dump=obj_dump \
add=q_add \
empty=q_empty \
full=q_full \
peek=q_peek \
remove=q_remove
class RoughQueue:Queue \
N=100 \
shove=q_shove \
head_drop=q_head_drop
Créé certaines instances de la file d'attente et les a fait fonctionner:
class Q:Queue N=1000
$Q add aaa bbb "ccc ddd"
$Q peek X
$Q remove X
printf "X=%s\n" "$X"
$Q remove X
printf "X=%s\n" "$X"
$Q remove X
printf "X=%s\n" "$X"
class R:RoughQueue N=3
$R shove aa bb cc dd ee ff gg hh ii jj
$R dump
ksh93t + introduit certains OO concepts tout en conservant la syntaxe de BOURNE/POSIX Shell: http://blog.fpmurphy.com/2010/05/ksh93-utilisation-types-a- Créer-Object-orienté-scripts.html
ipython est étonnamment pratique à utiliser.
CARACTÉRISTIQUES STANDARD Shell: Contrôle de la tâche, Édition LIVELLINE et HISTORION, Alias, cat
_ _ ls
_ cd
et pwd
, intégration de pager, exécutant toute commande système en le préfixant avec un !
ou activant %rehashx
, la sortie de commande assignable à A python variable, python valeurs disponibles en tant que variables de shell.
Python-spécifique: la réutilisation des résultats des dernières commandes, un accès rapide à la documentation et à la source, le rechargement du module, le débogueur. Un support de cluster si vous êtes dans cela.
Cela dit, le fonctionnement des tuyaux complexes n'est pas fait en python; Vous utiliserez également la coquille POSIX, juste avec une certaine colle pour transmettre des valeurs et votre.
Celui-ci est un peu plus simple à utiliser et à mettre en place, a nommé args, etc. https://github.com/uududruid74/bashtheObjects
Je mettez à jour ma réponse avec un exemple qui suit l'un des exemples de base donnés pour une autre réponse, mais avec cette syntaxe. Le programme d'exemple est similaire, mais vous n'avez pas à préfixer toutes les variables avec le nom de classe (elle le sait comme le type de montre) et je Pensez que la syntaxe est beaucoup Plus simple!
Premièrement, un fichier de classe. Les valeurs par défaut pour les variables d'instance sont facultatives et utilisées uniquement si vous ne transmettez pas ces valeurs dans le constructeur.
class Person
public show
public set
public Name
public Age
public Sex
inst var Name "Saranyan"
inst var Age 10
inst var Sex "Male"
Person::Person { :; }
Person::set() { :; }
Person::Name() { println $Name }
Person::Age() { println $Age }
Person::Sex() { println $Sex }
Person::show() {
Person::Name
Person::Age
Person::Sex
}
Maintenant, par exemple, utilisation:
#!/bin/bash
source static/oop.lib.sh
import Person
new Person Christy Name:"Christy" Age:21 Sex:"female"
new Person Evan Name:"Evan" Age:41 Sex:"male"
println "$(Evan.Name) is a $(Evan.Sex) aged $(Evan.Age)"
println "$(Christy.Name) is a $(Christy.Sex) aged $(Christy.Age)"
println "Stats for Evan ..."
Evan.show
assert 'kindof Person Evan'
assert '[ $Evan = $Evan ]'
assert 'kindof Person Christy'
assert '[ $Evan = $Christy ]'
REMARQUES:
L'instruction d'importation n'est techniquement pas requise, mais elle force le chargement de la classe au point donné au lieu d'attendre le premier nouveau , qui peut aider à initialiser les choses dans le bon ordre. Notez la facilité pour laquelle vous pouvez définir plusieurs variables d'instance à la fois.
Il existe également des niveaux de débogage, des constructeurs, destructeurs, Sous-classement et un système de base réflexion Système et montré est Imprimer/PrintLN = Pour remplacer ECHO (essayez jamais d'imprimer une variable qui commence par un tiret?). L'exemple sur GitHub montre qu'il fonctionne en tant que CGI générant HTML de classes.
La bibliothèque elle-même (oop.lib.sh) n'est pas aussi simple (400 lignes, 11k), mais vous n'incluez pas cela et l'oublier.
Vous pouvez installer PowerShell Core Edition sur Linux maintenant. Il fonctionne sur le cadre de base de la plate-forme multiplate-forme qui est activement développé par Microsoft.
jq
fonctionne assez bien comme une sorte de couche orientée objet.
Ceci est une coquille orientée objet basée à Python, mais elle a une fermeture Sintaxe de Golang: https://github.com/alexst07/shell-plus-plus
Par exemple, essayez d'attraper:
try {
git clone [email protected]:alexst07/Shell-plus-plus.git
} catch InvalidCmdException as ex {
print("git not installed [msg: ", ex, "]")
}
surcharge de classe et de l'opérateur:
class Complex {
func __init__(r, i) {
this.r = r
this.i = i
}
func __add__(n) {
return Complex(n.r + this.r, n.i + this.i)
}
func __sub__(n) {
return Complex(n.r - this.r, n.i - this.i)
}
func __print__() {
return string(this.r) + " + " + string(this.i) + "i"
}
}
c1 = Complex(2, 3)
c2 = Complex(1, 2)
c = c1 + c2
print(c)
et vous pouvez utiliser les commandes similaires bash:
echo "Test" | cat # simple pipeline
ls src* | grep -e "test" # using glob
# using variables content as command
cip = "ipconfig"
cgrep = ["grep", "-e", "10\..*"]
${cip} | $@{cgrep} # pass an array to command
Si quelqu'un ne veut que les bases de la programmation orientée objet (propriétés et méthodes) qu'un cadre vraiment simple ferait le tour.
Disons que vous souhaitez afficher le texte "Hello World" en utilisant des objets. Vous créez d'abord une classe d'objet qui a une propriété pour le texte à afficher et dispose de certaines méthodes pour définir ce texte et l'afficher. Pour montrer comment plusieurs instances d'une classe peuvent travailler ensemble, j'ai ajouté deux méthodes d'affichage du texte: une avec nouvelle ligne à la fin et une sans cela.
Fichier de définition de classe :échoclass.class
# Define properties
<<InstanceName>>_EchoString="Default text for <<InstanceName>>"
# Define methods
function <<InstanceName>>_SetEchoString()
{
<<InstanceName>>_EchoString=$1
}
function <<InstanceName>>_Echo()
{
# The -ne parameter tells echo not to add a NewLine at the end (No Enter)
echo -ne "$<<InstanceName>>_EchoString"
}
function <<InstanceName>>_EchoNL()
{
echo "$<<InstanceName>>_EchoString"
}
Veuillez noter le mot "<<nom d'instance >>". Cela sera remplacé ultérieurement pour créer plusieurs instances d'un objet de classe. Avant de pouvoir utiliser une instance d'un objet, vous avez besoin d'une fonction qui le crée en réalité. Pour garder les choses simples, ce sera un script distinct appelé: objetframework.lib
# 1st parameter : object instance name
# 2nd parameter : object instance class
function CreateObject()
{
local InstanceName=$1
local ObjectClass=$2
# We will replace all occurences of the text "<<InstanceName>>" in the class file
# to the value of the InstanceName variable and store it in a temporary file
local SedString='s/<<InstanceName>>/'$InstanceName'/g '$ObjectClass'.class'
local TmpFile=$ObjectClass'_'$InstanceName'.tmp'
sed $SedString > $TmpFile
# The file will contain code which defines variables (properties) and functions (methods)
# with the name we gave to our object instance via the 1st parameter of this function
# ... we run this code so the variables and functions are actually defined in runtime
source "$TmpFile"
# Than remove the temp file as we don't need it any more
rm "$TmpFile"
}
Alors maintenant, nous avons un fichier de définition de classe et une fonction CreateObject qui crée une copie de ce fichier avec le texte "<<nom InstanceName>>" remplacé par n'importe quel nom que nous voulons.
Utilisons notre nouvel objet dans un script appelé: helloworld.sh (Veuillez noter que helloworld.sh doit être exécutable. Les deux autres fichiers n'ont pas besoin de)
# Define the CreateObject function via the lib file we created
source ObjectFramework.lib
# Create two instances of the EchoClass class
CreateObject MyHello EchoClass
CreateObject MyWorld EchoClass
# Call the SetEchoString method of the two objects. In reality these are
# just two identical functions named differently and setting different
# variables (remember the <<InstanceName>>_EchoString variable?)
MyHello_SetEchoString "Hello "
MyWorld_SetEchoString "World"
# Finally we call the Echo and EchoNL (NewLine) methods
MyHello_Echo
MyWorld_EchoNL
En exécutant le script helloworld.sh, il affiche le texte "Hello World" (et ajoute une nouvelle ligne). Personne ne sera beaucoup impressionné par ce résultat, mais nous saurons que ce n'est pas aussi simple qu'il ressemble à :)
Joyeux codage!
## implemantion of base class
function Class()
{
base=${FUNCNAME}
this=${1}
Class_setCUUID $this
for method in $(compgen -A function)
do
export ${method/#$base\_/$this\_}="${method} ${this}"
done
}
function copyCUUID()
{
export ${2}_CUUID=$(echo $(eval "echo \$${1}_CUUID"))
}
function Class_setCUUID()
{
export ${1}_CUUID=$(uuid)
}
function Class_getCUUID()
{
echo $(eval "echo \$${2}_CUUID")
}
function Class_setProperty()
{
export ${1}_${2}=${3}
}
function Class_getProperty()
{
echo $(eval "echo \$${1}_${2}")
}
function Class_Method()
{
echo "function ${1}_${2}()
{
echo null
}
" > /tmp/t.func
. /tmp/t.func
rm /tmp/t.func
}
function Class_setMethod()
{
export ${1}_${2}=${1}_${2}
}
function Class_getMethod()
{
$(eval "echo \$${1}_${2}")
}
function Class_equals()
{
base="Class"
this=${2}
copyCUUID ${1} ${2}
for method in $(compgen -A function)
do
export ${method/#$base\_/$this\_}="${method} ${1}"
done
}
vient d'essayer d'introduire des concepts OO à baster en fonction de la référence http://hipersayanx.blogspot.in/2012/12/Object-oriented-programming-in-bash.html
source ./oobash
Class person
$person_setProperty Name "Saranyan"
$person_setProperty Age 10
$person_setProperty Sex "Male"
function person_show()
{
$person_getProperty Name
$person_getProperty Age
$person_getProperty Sex
}
$person_setMethod show
$person_equals person1
$person1_getMethod show
$person1_equals person3
$person_getCUUID person
$person_getCUUID person1
$person_getCUUID person3
plumbum est un langage de shell de type python. IT Forfait Shell comme syntaxe avec Python Rendre l'expérience orientée objet.
Maintenant, avec quels objets traitez-vous dans une coquille la plupart du temps? Ce sont des fichiers/des annuaires, des processus et leur interaction. Donc, il devrait aimer f1.edit
Ou quelque chose comme currentFile=f1.c ; .edit ; .compile ; .run
. Ou d1.search(filename='*.c' string='int \*')
. Ou p1.stop
, p1.bg
. C'est ma compréhension d'un ooshell.
Désolé pour la courte réponse mais voici.
hipersayanx a créé un article Programmation orientée objet dans Bash . Fondamentalement, il hi-jacked $FUNCNAME
, function
, compgen
et export
_ Pour créer aussi près de OOP ONE ONE PEUT ÊTRE EN BASH.
La partie cool est-ce que cela fonctionne bien et une seule a besoin de quelques lignes de chaudronnage pour construire une classe.
Les pièces de base nécessaires sont:
ClassName() {
# A pointer to this Class. (2)
base=$FUNCNAME
this=$1
# Inherited classes (optional).
export ${this}_inherits="Class1 Class2 Class3" # (3.1)
for class in $(eval "echo \$${this}_inherits")
do
for property in $(compgen -A variable ${class}_)
do
export ${property/#$class\_/$this\_}="${property}" # (3.2)
done
for method in $(compgen -A function ${class}_)
do
export ${method/#$class\_/$this\_}="${method} ${this}"
done
done
# Declare Properties.
export ${this}_x=$2
export ${this}_y=$3
export ${this}_z=$4
# Declare methods.
for method in $(compgen -A function); do
export ${method/#$base\_/$this\_}="${method} ${this}"
done
}
function ClassName_MethodName()
{
#base is where the magic happens, its what holds the class name
base=$(expr "$FUNCNAME" : '\([a-zA-Z][a-zA-Z0-9]*\)')
this=$1
x=$(eval "echo \$${this}_x")
echo "$this ($x)"
}
Usage:
# Create a new Class Instance
ClassName 'instanceName' $param1 $param2
$instanceName_method
Maintenant, je m'en ai utilisé moi-même dans mon projet Auditops et Hipersayanx dispose de plus amples détails sur la manière dont cela fonctionne réellement sur son site. AVERTISSEMENT FARE Bien que ce soit très bashisme ne fonctionnera pas avec quelque chose de plus âgé que Bash 4.0 et peut conduire à un mal de tête dans le débogage. Personnellement, j'aimerais voir la majeure partie de la chaudière placée refaire comme une classe elle-même.
Il est toujours plus sage d'utiliser un OOP Langage de script comme Perl, Ruby et python une fois mieux adapté à votre projet. Cependant, dans mon honnête option sa valeur temps et effort lors de la maintenance des scripts de bash modulaires pour utiliser cette méthode de OOP à bash.
Je développe une fonction GitHub une fonction qui fonctionne comme un objet HASHMAP , shell_map .
Afin de créer des instances de hashmap "" Cette fonction est capable de créer des copies de lui-même sous différents noms. Chaque nouvelle copie de fonctions aura une variable de dollaphname de $ différente. $ Funcname est alors utilisé pour créer un espace de noms pour chaque instance de carte.
Les clés de la carte sont des variables globales, dans la clé $ Funcname_Data_ $ clé, où $ Key est la clé ajoutée à la carte. Ces variables sont variables dynamiques .
Soufflé, je vais mettre une version simplifiée de cela afin que vous puissiez utiliser comme exemple.
#!/bin/bash
Shell_map () {
local METHOD="$1"
case $METHOD in
new)
local NEW_MAP="$2"
# loads Shell_map function declaration
test -n "$(declare -f Shell_map)" || return
# declares in the Global Scope a copy of Shell_map, under a new name.
eval "${_/Shell_map/$2}"
;;
put)
local KEY="$2"
local VALUE="$3"
# declares a variable in the global scope
eval ${FUNCNAME}_DATA_${KEY}='$VALUE'
;;
get)
local KEY="$2"
local VALUE="${FUNCNAME}_DATA_${KEY}"
echo "${!VALUE}"
;;
keys)
declare | grep -Po "(?<=${FUNCNAME}_DATA_)\w+((?=\=))"
;;
name)
echo $FUNCNAME
;;
contains_key)
local KEY="$2"
compgen -v ${FUNCNAME}_DATA_${KEY} > /dev/null && return 0 || return 1
;;
clear_all)
while read var; do
unset $var
done < <(compgen -v ${FUNCNAME}_DATA_)
;;
remove)
local KEY="$2"
unset ${FUNCNAME}_DATA_${KEY}
;;
size)
compgen -v ${FUNCNAME}_DATA_${KEY} | wc -l
;;
*)
echo "unsupported operation '$1'."
return 1
;;
esac
}
Usage:
Shell_map new credit
credit put Mary 100
credit put John 200
for customer in `credit keys`; do
value=`credit get $customer`
echo "customer $customer has $value"
done
credit contains "Mary" && echo "Mary has credit!"