web-dev-qa-db-fra.com

Shell orienté objet pour * Nix

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?

42
Robert S Ciaccio

Je peux penser à trois caractéristiques souhaitables dans une coquille:

  • Utilisation interactive: les commandes communes doivent être rapides à taper; achèvement; ...
  • Programmation: structures de données; Concurrence (emplois, pipe, ...); ...
  • Accès au système: Utilisation de fichiers, de processus, de fenêtres, de bases de données, de configuration système, ...

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:

  • BC pour des mathématiques simples
  • OpenSSL pour la cryptographie
  • SED , awk et autres pour le traitement de texte
  • NC pour la mise en réseau TCP/IP de base
  • ftp pour ftp
  • mail, Mail, mailx, etc. pour un courrier électronique de base
  • cron pour des tâches planifiées
  • WMCTRL pour la manipulation de base de base x
  • DCOP pour les bibliothèques KDE ≤3.x
  • DBUS Outils (dbus-* 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:

  • La plupart des périphériques matériels sont accessibles en tant que fichiers.
  • Sous Linux, /sys fournit plus de matériel et de contrôle du système.
  • Sur de nombreuses variantes UNIX, le contrôle des processus peut être effectué à travers le /proc système de fichiers.
  • fusible Il est facile d'écrire de nouveaux systèmes de fichiers. Il existe déjà des systèmes de fichiers existants pour la conversion de formats de fichier à la volée, accédant à des fichiers sur divers protocoles de réseau, à la recherche d'archives à l'intérieur, etc.

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
14
philcolbourn

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

7
jlliagre

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.

5
Tobu

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:

  1. Cette dernière assertion échouera. Contrairement à l'exemple ci-dessus, la bibliothèque ne supporte pas encore l'affectation d'objet, mais cela ne serait pas trop difficile à ajouter. Je vais le placer sur mon à faire avec le prochain support de conteneur/itérateur.

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.

2
Evan Langlois

Il y a - Rush Quel utilise Ruby et PSH qui est basé sur Perl.

2
OneOfOne

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.

2
Trevor Sullivan

jq fonctionne assez bien comme une sorte de couche orientée objet.

2
Abbafei

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
1
Alex

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!

1
vandor76
## 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
0

plumbum est un langage de shell de type python. IT Forfait Shell comme syntaxe avec Python Rendre l'expérience orientée objet.

0
joshlk

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.

0
ott--

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.

0
Dwight Spencer

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!"
0