* nixのオブジェクト指向シェル


38

序文:私はbashが大好きで、いかなる種類の議論や聖戦を始めるつもりもありません。これは非常に素朴な質問ではありません。

この質問はスーパーユーザーに関するこの投稿に多少関係していますが、OPが彼が何を求めているのかを本当に知っているとは思いません。FreeBSD、Linux、OS X、およびWindowsのcygwinでbashを使用しています。また、最近、Windows上のPowerShellで広範な経験を積んでいます。

bashと互換性があるが、ミックスにオブジェクト指向のスクリプトのレイヤーを追加する、* nix用のシェルが既に利用可能または作業中です。私が知っている唯一のものは近くにあるPythonコンソールですが、私が知る限り、それは標準シェル環境へのアクセスを提供していません。例えば、私がいないだけでできcd ~ls、その後chmod +x fileのpythonコンソールの内部。これらのタスクを実行するには、標準のUNIXバイナリではなくpythonを使用するか、pythonコードを使用してバイナリを呼び出す必要があります。

そのようなシェルは存在しますか?


3
Pashがありますが、これはBashのようなPowershellのようなものです。
一時的な

1
@ephemientおそらくpashの答えを書く必要があります...それについては何も知りませんが、iirc、powershellはOOシェルです。
xenoterracide

4
ちょっと、あなたはipythonをチェックアウトする必要があります。pythonとして意味をなさない式を入力すると、それをシェルコマンドにマップしようとします。たとえば、bashのようcd ~ls動作するようなものは動作します。また、listing = !ls
直観

@intuited:素晴らしい、私はそれをチェックします
ロバートSチャシオ

1
@intuited:iPythonは私がやりたいことに対してかなり良いものでした、ありがとう!
ロバートSチャシオ

回答:


43

シェルの3つの望ましい機能を考えることができます。

  • インタラクティブな使いやすさ:一般的なコマンドはすばやく入力する必要があります。完了; ...
  • プログラミング:データ構造。並行性(ジョブ、パイプ、...); ...
  • システムアクセス:ファイル、プロセス、ウィンドウ、データベース、システム構成などの操作

Unixシェルは、対話的な側面に集中する傾向があり、システムアクセスのほとんどと、次のような外部ツールへのプログラミングの一部を下請けします。

  • 単純な数学のためのbc
  • 暗号化のためのopenssl
  • テキスト処理のためのsedawkなど
  • 基本的なTCP / IPネットワーキング用のnc
  • ftp FTP用
  • mailMailmailx、などの基本的な電子メールのための
  • cron スケジュールされたタスク用
  • 基本的なXウィンドウ操作のためのwmctrl
  • KDE≤3.xライブラリのdcop
  • さまざまなシステム情報および構成タスク用のdbusツール(dbus-*またはqdbus)(KDE≥4などの最新のデスクトップ環境を含む)

適切な引数またはパイプ入力を使用してコマンドを呼び出すことにより、多くのことができます。これは非常に強力なアプローチです。タスクごとに1つのツールを使用する方がうまく機能しますが、1つのプログラムがひどくすべてを実行するよりも優れています。

UNIXシェルの主な制限は、「オブジェクト指向スクリプト」の要件を満たしていることです。コマンド間で情報を保持したり、コマンドをより巧妙に組み合わせたりするのが苦手です。パイプライン。特に、プログラム間通信はテキストベースであるため、アプリケーションは、互換性のある方法でデータをシリアル化する場合にのみ組み合わせることができます。これは祝福でもあり呪いでもあります。すべてがテキストであるというアプローチは、単純なタスクを簡単にすばやく実行できるようにしますが、より複雑なタスクの障壁を高めます。

インタラクティブなユーザビリティも、プログラムの保守性に反するものです。対話型プログラムは短く、引用符をほとんど必要とせず、変数宣言や入力などに煩わされません文字列、関数名、変数名など)、変数宣言や入力などの一貫性チェックが必要です。

要約すると、シェルは到達するのが難しい妥協です。OK、これで暴言のセクションを終了します。


  • Perlのシェル(PSH)は、「PerlののパワーとUnixのシェルのインタラクティブな性質を兼ね備えて」。単純なコマンド(パイプラインも)をシェル構文で入力できます。それ以外はすべてPerlです。このプロジェクトは長い間開発されていません。使用できますが、純粋なPerl(スクリプト用)または純粋なシェル(対話式またはスクリプト用)で使用することを検討するポイントには達していません。

  • IPythonは、特に数値計算および並列計算を対象とした、改善された対話型Pythonコンソールです。これは比較的若いプロジェクトです。

  • irb(インタラクティブルビー)は、Pythonコンソールに相当するRubyです。

  • scshは、unixシェル(文字列、プロセス、ファイル)に伝統的に見られる種類のシステムバインディングを持つスキーム実装(つまり、適切なプログラミング言語)です。ただし、インタラクティブシェルとして使用できるようにはなっていません。

  • zshは改善された対話型シェルです。その長所は、対話性(コマンドライン版、完了、簡潔でありながら不可解な構文で実行される一般的なタスク)です。そのプログラミング機能はそれほど優れていませんが(kshと同等)、端末制御、正規表現、ネットワーキングなどのためのライブラリが多数付属しています。

  • は、Unixスタイルのシェルでのクリーンスタートです。優れたプログラミング機能やシステムアクセス機能はありません。shとの互換性を損なうため、より良い機能を進化させる余地がありますが、それは実現していません。


補遺:UNIXツールボックスの別の部分は、多くのものをファイルとして扱っています。

  • ほとんどのハードウェアデバイスはファイルとしてアクセス可能です。
  • Linuxでは、/sysより多くのハードウェアとシステムの制御を提供します。
  • 多くのUNIXバリアントでは、プロセス制御は/procファイルシステムを介して実行できます。
  • FUSEを使用すると、新しいファイルシステムを簡単に作成できます。オンザフライでファイル形式を変換したり、さまざまなネットワークプロトコルを介してファイルにアクセスしたり、アーカイブ内を検索したりするための既存のファイルシステムが既にあります。

UNIXシェルの将来は、コマンドによるシステムアクセスの改善(およびコマンドを結合するための制御構造の改善)ではなく、ファイルシステムによるシステムアクセスの改善(多少異なる組み合わせです—キーイディオム(シェルパイプ)はまだです)。


1
「これがあなたの狙いだと思う」と言った直後に頭に釘を打ちます。私がこの質問をしている主な理由は、Unixツールの力を持っているのが好きだからです。しかし、プログラム間のテキストベースの相互作用は間違いなく「より複雑なタスクの障壁を高めます」。私はプログラミングに十分な時間を費やしてテキストパーサーを作成しました:)これは非常によく考えられた答えだと思います。それは問題の核心と主題の複雑さをもたらします。私はそれを2回upvoteことがしたい:P
ロバート・S Ciaccio

1
ipythonの+1ですが、OPが何をしたいのかわかりません。
ファルマーリ

1
これは素晴らしい答えです。正直、興味深い博士論文の種はここにあると思います。
ジギー

1
@RobertSCiaccioこの回答は最近の投稿でリンクされただけで、テキスト解析に関するコメントは私に考えさせられました...テキスト解析が「複雑なタスク」を達成するのに十分であれば、それを実装する小さなスクリプトまたはプログラムはありませんでしたそれをあなたのbashスクリプトの何らかの機能として使用しますか?考えてみれば、私は言うまでもなく、bashスクリプトの経験はあまりありません。
オックスウィビ14

1
@onlyanegg魚はどのようにして「オブジェクト指向」と言えるでしょうか?魚は主にシンプルであることを目指しています。代替手段よりも強力な方法はありますか?
ジル「SO-停止されて悪」

13

クラスまたはオブジェクトをbashに実装するのに、多くのbashコードは必要ありません。

たとえば、100行です。

Bashには、継承、メソッド、およびプロパティを持つ単純なオブジェクトシステムを実装するために使用できる連想配列があります。

したがって、次のようなクラスを定義できます。

class Queue N=10 add=q_add remove=q_remove

このキューのインスタンスを作成するには、次のようにします。

class Q:Queue N=100

または

inst Q:Queue N=100

クラスは配列で実装されているため、クラスinstは実際には同義語です-javascriptのようなものです。

このキューにアイテムを追加するには、次のようにします。

$Q add 1 2 aaa bbb "a string"

変数Xへのアイテムの削除は、次のように実行できます。

$Q remove X

オブジェクトの構造をダンプするには、次のようにします。

$Q dump

これは次のようなものを返します:

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=
    }

クラスは、次のようなクラス関数を使用して作成されます。

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"
}

注:新しいクラスまたはインスタンスを定義するときに、メンバーの値または関数をオーバーライドできます。

Bash連想配列には、これをうまく機能させる癖があります。$ Q [0]}は$ Qと同じです。これは、配列名を使用してメソッドディスパッチ関数を呼び出すことができることを意味します。

dispatch(){
    local _this=$1 _method=$2 _fn
    shift 2
    _fn="$_this[$_method]"                       # reference to method name
    ${!_fn} $_this "$@"
}

欠点は、データに[0]を使用できないため、キュー(この場合)がindex = 1から始まることです。あるいは、「q + 0」のような連想インデックスを使用することもできます。

メンバーを取得および設定するには、次のようにします。

# 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
}

そして、オブジェクト構造をダンプするために、私はこれを作りました:

注:これはbashのOOPには必要ありませんが、オブジェクトがどのように作成されるかを見ると便利です。

# 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
}

私のOOP設計では、継承されたクラスを除き、オブジェクト内のオブジェクトを考慮していません。それらを個別に作成することも、class()のような特別なコンストラクターを作成することもできます。* obj_dump *は、内部クラスを検出して再帰的に出力するように変更する必要があります。

ああ!そして、クラス関数を簡素化するためにROOTクラスを手動で定義します。

declare -gA ROOT=(    \
  [this]=ROOT         \
  [0]="dispatch ROOT" \
  [dump]=obj_dump     \
  [set]="ROOT_set"    \
  [get]="ROOT_get"    \
)

いくつかのキュー関数を使用して、次のようなクラスを定義しました。

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

いくつかのQueueインスタンスを作成し、それらを機能させました:

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

動作しますが、それはだかもしれない醜いです。そして、それは何のbashためではありません。テキストを処理するためにシェルループを使用しない理由についてのStephaneの答え、特にCとのような言語間の目的の違いを詳述する「概念的に」という見出しのセクションを思い出しますbashunix.stackexchange.com/a/169765/135943
ワイルドカード

1
うまくいくでしょうか?それは機能しますが、あなたのポイントは、間違っていませんが、それが行われていないということです。OPの質問にも答えませんでしたが、bashがTCの場合、オブジェクトを処理できるはずだと考えました。そして、多くの人がこれを実証しています。
フィルコルボーン


5

IPythonは驚くほど便利に使用できます。

標準シェル機能:ジョブ制御、readline編集と履歴、エイリアス、cat ls cdおよびpwdページャー統合、接頭辞!または有効化によるシステムコマンドの実行%rehashx、python変数に割り当て可能なコマンド出力、python値はシェル変数として使用可能。

Python固有:最後のコマンドの結果の再利用、ドキュメントとソースへの迅速なアクセス、モジュールの再読み込み、デバッガー。あなたがそれに興味を持っている場合、いくつかのクラスタをサポートします。

とはいえ、複雑なパイプの実行はPythonでは行われません。posixシェルも使用し、値をやり取りするための接着剤を使用します。




2

これは使用とセットアップが少し簡単で、argsなどの名前が付いてい ます。https://github.com/uudruid74/bashTheObjects

別の回答の基本的な例の1つに続きますが、この構文を使用した例を使用して、回答を更新しています。サンプルプログラムは似ていますが、すべての変数にクラス名を付ける必要はありません(kindofメソッドが示すようにこれを知っています)。構文はもっと簡単だと思います!

まず、クラスファイル。インスタンス変数のデフォルトはオプションであり、これらの値をコンストラクターに渡さない場合にのみ使用されます。

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
}

次に、使用例を示します。

#!/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 ]'

ノート:

  1. その最後のアサーションは失敗します。上記の例とは異なり、ライブラリはまだオブジェクトの割り当てをサポートしていませんが、追加するのはそれほど難しくありません。今後のコンテナ/イテレータサポートとともに、TO-DOに配置します。

importステートメントは技術的には必要ありませんが、最初のnewを待つのではなく、指定されたポイントでクラスのロードを強制します。これにより、適切な順序で初期化できます。複数のインスタンス変数を一度に設定できる容易さに注意してください。

デバッグレベル、コンストラクタ、デストラクタ、サブクラス化、および基本的なリフレクションシステムもあり、エコーを置き換えるprint / printlnが示されています(ダッシュで始まる変数を印刷しようとすることはありますか?)。githubの例では、クラスからHTMLを生成するCGIとして実行されています。

ライブラリ自体(oop.lib.sh)はそれほど単純ではありません(400行以上、11K)が、それを含めるだけで忘れてしまいます。



1

誰かがオブジェクト指向プログラミングの基本(プロパティとメソッド)だけを望んでいるなら、本当にシンプルなフレームワークがトリックをするでしょう。

オブジェクトを使用して「Hello World」というテキストを表示するとします。最初に、表示するテキストのプロパティと、このテキストを設定して表示するいくつかのメソッドを持つオブジェクトクラスを作成します。クラスの複数のインスタンスがどのように連携するかを示すために、テキストを表示するための2つのメソッドを追加しました。

クラス定義ファイル:EchoClass.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"
}

「<<InstanceName>>」という単語に注意してください。これは、クラスオブジェクトの複数のインスタンスを作成するために後で置き換えられます。オブジェクトのインスタンスを使用する前に、実際に作成する関数が必要です。物事を単純にするために、ObjectFramework.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"
}

クラス定義ファイルと、このファイルのコピーを作成するCreateObject関数があります。この関数は、テキスト「<<InstanceName>>」を任意の名前に置き換えます。

HelloWorld.shというスクリプトで新しいオブジェクトを使用してみましょう (HelloWorld.shは実行可能である必要があります。他の2つのファイルは必要ありません)。

# 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

HelloWorld.shスクリプトを実行すると、「Hello World」というテキストが表示されます(そして、NewLineが追加されます)。この結果に誰も感心することはありませんが、これは次のように単純ではないことがわかります:)

ハッピーコーディング!


単純なものを複雑にするよりも、複雑なものを単純にする方が良いです。
ワイルドカード

1

これはPythonベースのオブジェクト指向シェルですが、Golangに近い構文がありますhttps : //github.com/alexst07/shell-plus-plus

たとえば、catchを試してください。

try {
  git clone git@github.com:alexst07/shell-plus-plus.git
} catch InvalidCmdException as ex {
  print("git not installed [msg: ", ex, "]")
}

クラスと演算子のオーバーロード:

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)

また、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

0

さて、ほとんどの場合、シェルではどのオブジェクトを扱っていますか?ファイル/ディレクトリ、プロセス、およびそれらの相互作用です。だからそれは好きf1.editか何かのようにする必要がありcurrentFile=f1.c ; .edit ; .compile ; .runます。またはd1.search(filename='*.c' string='int \*')。またはp1.stopp1.bg。それがooshellの私の理解です。


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


}

参照http://hipersayanx.blogspot.in/2012/12/object-oriented-programming-in-bash.htmlに基づいてooの概念をbashに導入しようとしました

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

短い返信で申し訳ありませんが、ここに行きます。

hipersayanxはBashでのオブジェクト指向プログラミングの記事を作成しました。基本的に彼がhi-ジャッキ$FUNCNAMEfunctioncompgen、およびexport1はbashで得ることができるOOPの近くに作成します。

クールな部分はそれがうまく機能し、クラスを構築するのにボイラーメッキの数行を必要とするだけです。

必要な基本部品は次のとおりです。

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)"
}

使用法:

# Create a new Class Instance
ClassName 'instanceName' $param1 $param2

$instanceName_method

今、私は自分のAuditOpsプロジェクトでこれを使用しており、hipersayanxがこれが彼のサイトで実際にどのように機能するかについて詳細に説明しています。これは非常にbashismですが、bash 4.0よりも古いものでは動作せず、デバッグで頭痛の種になる可能性があります。個人的には、ボイラーメッキのほとんどがクラス自体としてやり直されることを望みます。

プロジェクトに適している場合は、perl、ruby、pythonなどの本格的なOOPスクリプト言語を使用する方が常に賢明です。しかし、私の正直なオプションでは、bashでこのOOPの方法を利用するためにモジュラーbashスクリプトを保守するとき、時間と労力に値します。


0

私はGitHubの上で同じように動作機能開発していたHashMapオブジェクトshell_mapを

HashMapインスタンス」を作成するために、この関数は異なる名前で自身のコピーを作成できます。新しい関数のコピーごとに、異なる$ FUNCNAME変数があります。次に、$ FUNCNAMEを使用して、各Mapインスタンスの名前空間を作成します。

マップキーは、$ FUNCNAME_DATA_ $ KEYという形式のグローバル変数です。$ KEYは、マップに追加されたキーです。これらの変数は動的変数です

次の例として使用できるように、簡略化したバージョンを配置します。

#!/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
}

使用法:

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

コマンド置換の仕組みを誤解しているようです。backticksに含まれるコマンドの出力に置き換えられ、return statusには置き換えられません。言い換えれば、あなたのコードはあなたが思っていることをしません。
ワイルドカード

あぁ。あなたは正しいです。謝罪いたします。ただし、carp "Some error message"; return代わりに使用する方がはるかに明確です。
ワイルドカード

または[ -z "$KEY" ] && { carp "some message"; return;} サブシェルは必要ありません。しかし、実際には、それは実際のif ... elif ... elif ... else ... fi構成要素の候補のように見えます。これは、多くの場合最良の選択ではありませんが、おそらくここにあります。:)(または場合によっては切り替え)
ワイルドカード

@Wildcard答えを編集しました。今、コイとバックティックについての議論は意味がありません。この会話を削除しましょうか?
ブルーノネグランジカ

0

PlumbumはPythonに似たシェル言語です。Pythonでのシェルのような構文をパッケージ化し、エクスペリエンスをオブジェクト指向にします。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.