* Nix için nesne yönelimli kabuk


38

Önsöz: Ben bash'ı seviyorum ve herhangi bir argüman veya kutsal savaş başlatmaya niyetim yok ve umarım bu çok naif bir soru değildir.

Bu soru, biraz kullanıcı hakkında bu yazı ile ilgili, ancak OP ne istediğini gerçekten bildiğini sanmıyorum. FreeBSD'de bash, Windows'ta Linux, OS X ve cygwin kullanıyorum. Ayrıca son zamanlarda Windows'ta PowerShell ile ilgili geniş deneyimlerim oldu.

Halihazırda mevcut olan veya eserlerde bash ile uyumlu ancak karışıma bir nesne yönelimli komut dosyası katmanı ekleyen * nix için bir kabuk var mı? Bunu bildiğim tek şey yaklaşıyor python konsolu, ancak söyleyebildiğim kadarıyla standart kabuk ortamına erişim sağlayamıyor. Örneğin, sadece cd ~ve lssonra chmod +x filepython konsolunun içinde yapamam . Standart unix binaries yerine bu görevleri yerine getirmek için python kullanmam ya da python kodunu kullanarak ikili dosyaları çağırmam gerekirdi.

Böyle bir kabuk var mı?


3
Orada Pash ama bu çok daha Bash benzeri daha Powershell-gibi.
efemient

1
@ephemient belki pash için bir cevap yazmalısın ... bildiğim kadarıyla hiçbir şey bilmiyorum, iirc, powershell bir OO kabuğu.
xenoterracide

4
Hey, ipython'u kontrol etmelisin . Python anlamında olmayan bir ifade girerseniz, onu shell komutuyla eşlemeye çalışır. Örneğin, Bash'deki eserler cd ~tarafından takip edilenler gibi ls. Python değişkenlere atama çıkışı da yapabilirsiniz (çizgilerin listeleri.. Çeşit) gibi komutlarla listing = !ls.
intuited

@intuited: awesome, ben kontrol edeceğim
Robert S Ciaccio

1
@intuited: iPython yapmak istediğim şeyler için oldukça iyi oldu, teşekkürler!
Robert S Ciaccio

Yanıtlar:


43

Bir kabuğun içinde istenen üç özelliği düşünebilirim:

  • Etkileşimli kullanılabilirlik: yaygın komutlar hızlı yazılmalıdır; tamamlanması; ...
  • Programlama: veri yapıları; eşzamanlılık (iş, boru, ...); ...
  • Sistem erişimi: dosyalar, işlemler, pencereler, veritabanları, sistem yapılandırması, ... ile çalışma

Unix kabukları etkileşimli yön üzerinde yoğunlaşma eğilimindedir ve sistem erişiminin çoğunu ve programlamanın bir kısmını aşağıdaki gibi dış araçlara taşeronluk eder:

  • basit matematik için bc
  • şifreleme için openssl
  • metin işleme için sed , awk ve diğerleri
  • Temel TCP / IP ağı için nc
  • ftp FTP için
  • mail, Mail, mailxVb temel e-posta
  • cron zamanlanmış görevler için
  • Temel X pencere manipülasyonu için wmctrl
  • dcop KDE ≤3.x kütüphaneler için
  • Çeşitli sistem bilgileri ve yapılandırma görevleri için dbus araçları ( dbus-*veya qdbus ) (KDE ≥4 gibi modern masaüstü ortamları dahil)

Pek çok, birçok şey doğru argümanlar veya piped girişi olan bir komutu çağırarak yapılabilir. Bu çok güçlü bir yaklaşım - her işi iyi yapan tek bir programdan çok, her işi kötü yapan tek bir araçtan daha iyi - ama sınırlamaları var.

Unix kabukları için önemli bir sınırlamadır ve bence “nesne yönelimli komut dosyası” gereksiniminizin peşinde olduğunuz şey budur, bilgiyi bir komuttan diğerine saklamak ya da komutları meraklı bir şekilde birleştirmek için iyi değillerdir. bir boru hattı. Özellikle, programlar arası iletişim metin tabanlıdır, bu nedenle uygulamalar yalnızca verilerini uyumlu bir şekilde seriledikleri takdirde birleştirilebilir. Bu hem bir nimettir hem de bir lanettir: Her şey metindir yaklaşımı basit işleri hızlı bir şekilde yerine getirmeyi kolaylaştırır, ancak daha karmaşık görevlerin önündeki engelleri yükseltir.

Etkileşimli kullanılabilirlik, programın sürdürülebilirliğine karşı da çalışır. İnteraktif programlar kısa olmalı, çok az alıntı gerektirmeli, değişken bildirimler veya yazarak sizi rahatsız etmemelidir, vb. Bakım yapılabilir programlar okunabilir olmalıdır (bu nedenle çok fazla kısaltmaya sahip olmayın), okunabilir olmalıdır (bu nedenle çıplak bir kelime olup olmadığını merak etmenize gerek yoktur) dize, işlev adı, değişken adı vb.) Değişken bildirimleri ve yazma vb. gibi tutarlılık kontrolleri olmalıdır.

Özet olarak, bir kabuk ulaşmak zor bir uzlaşmadır. Tamam, bu örnekler üzerindeki rant bölümünü sonlandırıyor.


  • Perl Kabuk (psh) “Perl gücüyle Unix kabuğunun interaktif doğasını birleştirir”. Kabuk sözdiziminde basit komutlar (hatta boru hatları) girilebilir; her şey Perl. Proje uzun süredir geliştirilmemiştir. Kullanılabilir, ancak onu saf Perl (komut dosyası için) veya saf kabuk (etkileşimli olarak veya komut dosyası için) üzerinde kullanmayı düşündüğüm noktaya ulaşmadı.

  • IPython , özellikle sayısal ve paralel hesaplamayı hedef alan gelişmiş bir etkileşimli Python konsolu. Bu nispeten genç bir proje.

  • irb (etkileşimli yakut) , Python konsolunun Ruby eşdeğeridir.

  • scsh , geleneksel olarak unix kabuklarında (dizeler, işlemler, dosyalar) bulunan sistem bağlama türlerine sahip bir şema uygulamasıdır (yani iyi bir programlama dili). Bununla birlikte, etkileşimli bir kabuk olarak kullanılabilir olmayı hedeflememektedir.

  • zsh , geliştirilmiş bir etkileşimli kabuktur. Güçlü yanı etkileşimliliktir (komut satırı baskısı, tamamlama, kısa ve şifreli sözdizimi ile yapılan ortak görevler). Programlama özellikleri çok iyi değil (ksh ile eşit), ancak terminal kontrolü, regexps, ağ, vb. İçin bir takım kütüphanelerle birlikte geliyor.

  • Balık , unix tarzı bir kabukta temiz bir başlangıçtır. Daha iyi programlama veya sistem erişim özelliklerine sahip değildir. Sh ile uyumluluğu bozduğu için, daha iyi özellikler geliştirmek için daha fazla alana sahip, ancak bu olmadı.


Zeyilname: unix araç kutusunun bir başka kısmı da birçok şeyi dosya olarak ele almaktadır:

  • Çoğu donanım cihazına dosya olarak erişilebilir.
  • Linux altında /sysdaha fazla donanım ve sistem kontrolü sağlar.
  • Birçok unix varyantında, işlem kontrolü /procdosya sistemi üzerinden yapılabilir .
  • SİGORTA yeni dosya sistemleri yazmayı kolaylaştırır. Halihazırda dosya formatlarını dönüştürmek, çeşitli ağ protokolleri üzerinden dosyalara erişmek, arşivlere bakmak vb. İçin zaten mevcut dosya sistemleri mevcuttur.

Belki de unix kabuklarının geleceği komutlardan (ve komutları birleştirmek için daha iyi kontrol yapılarıyla) daha iyi sistem erişimi değil, dosya sistemlerinden daha iyi sisteme erişim (biraz daha farklı bir şekilde birleştirir) anahtar kelimelerinin ne olduğunu çözdüğümüzü sanmıyorum. Kabuk boru) henüz).


1
"Bundan sonra olduğundan şüpheliyim" dedikten hemen sonra kafasındaki tırnağa çarptın. Bu soruyu sormamın asıl nedeni, unix araçlarının gücüne sahip olmayı seviyorum ama programlar arasındaki metin tabanlı etkileşim kesinlikle 'daha karmaşık işler için bir engel oluşturuyor'. Programlama günlerimi metin ayrıştırıcıları yazmak için harcadım :) Bunun çok iyi düşünülmüş bir cevap olduğunu düşünüyorum. Konunun kalbine ve konunun karmaşıklığına ulaşıyor. Keşke iki kez daha fazla oy kullanabilseydim: P
Robert S Ciaccio

1
İpython için +1, OP'nin ne yapmak istediği hakkında hiçbir fikrim yok.
Falmarri

1
Bu harika bir cevap: Dürüst olmak gerekirse ilginç bir doktora tezinin tohumlarının burada olduğunu düşünüyorum.
Ziggy

1
@RobertSCiaccio Bu cevap daha yeni bir yayına bağlandı ve metin ayrıştırmalarla ilgili yorumunuz, "ayrıştırma işlemlerinizi" yerine getirmek için yeterliyse, metin ayrıştırma işlemi yeterliyse, uygulayan küçük bir komut veya programınız olamaz mıydı bash betiğinizde bir çeşit işlev olarak mı kullanıyorsunuz? Sadece bir düşünce, konuşmak için kemerimin altında bash komut dosyası deneyimi çok yok.
Oxwivi

1
@ onlyanegg Balıklar ne şekilde “nesne yönelimli” olarak söylenebilir? Balık öncelikle daha basit olmayı hedeflemektedir. Alternatiflerden daha güçlü bir yolu var mı?
Gilles 'SO- kötülük olmayı'

13

Bash'te sınıfları veya nesneleri uygulamak için çok fazla bash koduna ihtiyacınız yoktur.

100 çizgi söyle.

Bash, kalıtım, yöntemler ve özelliklerle basit bir Object sistemini uygulamak için kullanılabilecek ilişkisel dizilere sahiptir.

Yani, böyle bir sınıfı tanımlayabilirsiniz:

class Queue N=10 add=q_add remove=q_remove

Bu Kuyruğun bir örneğini oluşturmak şu şekilde yapılabilir:

class Q:Queue N=100

veya

inst Q:Queue N=100

Sınıflar bir dizi ile gerçekleştirildiğinden, sınıf ve inst gerçekten javascript'teki gibi eş anlamlıdır.

Bu kuyruğa eşya eklemek şu şekilde yapılabilir:

$Q add 1 2 aaa bbb "a string"

Öğeleri X değişkenine kaldırmak şu şekilde yapılabilir:

$Q remove X

Ve bir nesnenin damping yapısı şu şekilde yapılabilir:

$Q dump

Hangisi böyle bir şey döndürür:

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

Sınıflar şunun gibi bir sınıf işlevi kullanılarak oluşturulur:

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

NOT: Yeni bir sınıf veya örnek tanımlarken, herhangi bir üye değerini veya işlevi geçersiz kılabilirsiniz.

Bash ilişkisel dizilerinin bu çalışmayı düzgünce yapan bir tuhaflığı var: $ Q [0]} $ Q ile aynı. Bu, bir yöntem gönderme işlevini çağırmak için dizi adını kullanabileceğimiz anlamına gelir:

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

Aşağı tarafı, veri için [0] kullanamıyorum, bu yüzden sıralarım (bu durumda) index = 1'den başlıyor. Alternatif olarak "q + 0" gibi birleştirici dizinler kullanabilirdim.

To almak ve ayarlamak üyeleri böyle bir şey yapabilir:

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

Ve bir nesne yapısını terk etmek için şunu yaptım:

Not: Bu bash OOP için gerekli değildir, ancak nesnelerin nasıl yapıldığını görmek güzel.

# 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 tasarımım, devralınan sınıf dışında, nesnelerdeki nesneleri dikkate almadı. Bunları ayrı ayrı oluşturabilir veya class () gibi özel bir kurucu yapabilirsiniz. * obj_dump * içsel sınıfları tekrar tekrar basmak üzere tespit etmek için değiştirilmeliydi.

Ah! ve sınıf fonksiyonunu basitleştirmek için bir ROOT sınıfını manuel olarak tanımlarım :

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

Birkaç kuyruk fonksiyonuyla bunun gibi bazı sınıflar tanımladım:

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

Bazı Sıra örnekleri oluşturuldu ve çalışmalarını sağladı:

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

İşe yarayabilir ama çirkin . Ve kesinlikle bashbunun için değil . Stephane'nin metinleri işlemek için neden kabuk halka kullanmama konusundaki cevabını hatırlatıyor, özellikle de C ve bash. unix.stackexchange.com/a/169765/135943
Joker

1
Çalışabilir? İşe yarar, ancak amacınız, yanlış olmasa da, sadece yapılmamasıdır. OP sorusuna da cevap vermedim, ancak bash TC ise, nesneleri işlemesi gerektiğini düşündüm. Ve çoğu bunu kanıtladı.
Philcolbourn


5

IPython kullanımı şaşırtıcı derecede uygundur.

Standart kabuk özellikleri: iş kontrolü, okuma satırı düzenleme ve geçmişi, takma adlar, cat ls cd ve pwdçağrı cihazı entegrasyonu, herhangi bir sistem komutunu bir !ya da etkinleştirerek çalıştırarak çalıştırma %rehashx, bir python değişkenine atanan komut çıktısı, kabuk değişkenleri olarak kullanılabilen python değerleri.

Python'a özgü: son komutların sonuçlarını yeniden kullanma, belgelere ve kaynağa hızlı erişim, modül yeniden yükleme, hata ayıklayıcı. Bazı küme desteği, eğer buna katılıyorsanız.

Bununla birlikte, karmaşık boruların çalıştırılması Python'da yapılmıyor; posix kabuğunu da kullanacaksınız, sadece bazı değerleri yapıştırmak ve fro vermek için yapıştırıcı ile.



2

jq Bu tür bir nesne yönelimli katman gibi oldukça iyi çalışıyor.


2

Bu kullanımı ve kurulumu biraz daha basittir, args, vb. Https://github.com/uudruid74/bashTheObjects

Cevabımı, başka bir cevap için verilen temel örneklerden birini izleyen bir örnekle, ancak bu sözdizimiyle güncelliyorum. Örnek program benzerdir, ancak tüm değişkenleri sınıf adıyla öneklendirmek zorunda değilsiniz (bunu kindof yönteminin gösterdiği gibi bilir ) ve sözdiziminin çok daha basit olduğunu düşünüyorum !

İlk önce bir sınıf dosyası. Örnek değişkenleri için varsayılanlar isteğe bağlıdır ve yalnızca bu değerleri yapıcıya iletmezseniz kullanılır.

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
}

Şimdi örneğin kullanım için:

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

NOTLAR:

  1. Bu son iddia başarısız olacak. Yukarıdaki örnekten farklı olarak, kitaplık henüz nesne atamasını desteklemiyor, ancak eklemesi çok zor olmaz. Yakında yapılacak olan konteyner / yineleyici desteği ile birlikte TO-DO'ma yerleştireceğim.

İmport ifadesi teknik olarak gerekli değildir, ancak birinciyi beklemek yerine verilen noktaya sınıfın yüklenmesini zorlar. yeni doğru sırayla ilklendir şeyler yardımcı olabilir. Aynı anda birden fazla örnek değişkeni ayarlayabileceğiniz kolaylığı not alın.

Ayrıca hata ayıklama düzeyleri, yapıcılar, yıkıcılar, alt sınıflandırma ve temel bir yansıtma sistemi vardır. yankıyı değiştirmek print / println (hiç bir tire ile başlayan bir değişkeni yazdırmayı denediniz mi?). Github örneği, sınıflardan HTML üreten bir CGI olarak çalıştığını gösterir.

Kütüphanenin kendisi (oop.lib.sh) o kadar basit değildir (400+ satır, 11K), fakat sadece onu ekleyip unutuyorsunuz.



1

Eğer birisi sadece nesne yönelimli programlamanın temellerini (özellikler ve yöntemler) gerçekten basit bir çerçeveden çok isterse hile yapardı.

Nesneleri kullanarak "Merhaba Dünya" metnini görüntülemek istediğinizi varsayalım. Öncelikle, görüntülenecek metnin özelliğine sahip ve bu metni ayarlamak ve görüntülemek için bazı yöntemler içeren bir nesne sınıfı oluşturursunuz. Bir sınıfın birden fazla örneğinin birlikte nasıl çalışabileceğini göstermek için, metni görüntülemek için iki yöntem ekledim: biri sonunda NewLine ve biri olmadan.

Sınıf tanımı dosyası: 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"
}

Lütfen "<<ÖrnekAdı>>" kelimesini not edin. Bu daha sonra bir sınıf nesnesinin birden fazla örneğini oluşturmak için değiştirilecektir. Bir nesnenin örneğini kullanmadan önce, onu yaratan bir işleve ihtiyacınız vardır. Her şeyi basit tutmak için ayrı bir script olacaktır: 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"
}

Şimdi bir sınıf tanım dosyamız ve bu dosyanın bir kopyasını "<<ÖrnekAdı>>" metni ile değiştiren, istediğimiz ismin yerine geçen bir CreateObject işlevimiz var.

Yeni nesneyi HelloWorld.sh adlı bir komut dosyasında kullanalım: ( HelloWorld.sh dosyasının çalıştırılabilir olması gerektiğini lütfen unutmayın. Diğer iki dosyanın gerekmediğini unutmayın)

# 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 betiğini çalıştırarak "Merhaba Dünya" metnini görüntüler (ve bir NewLine ekler). Hiç kimse bu sonuçtan çok etkilenmeyecek, ancak bunun göründüğü kadar basit olmadığını biliyoruz :)

Mutlu kodlama!


Karmaşık şeyleri basitleştirmek, basit şeyleri karmaşık yapmaktan daha iyidir.
Wildcard

1

Bu Python merkezli nesne yönelimli bir kabuk, ancak Golang'ın yakın bir sintaksı var: https://github.com/alexst07/shell-plus-plus

Örneğin, yakalamayı deneyin:

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

sınıf ve operatör aşırı yüklenmesi:

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)

ve benzer bash komutlarını kullanabilirsiniz:

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

Şimdi, çoğu zaman kabuğunda hangi nesnelerle uğraşıyorsunuz? Dosyalar / dizinler, işlemler ve etkileşimleri. Bu yüzden sevmeli f1.editya da onun gibi bir şey olmalı currentFile=f1.c ; .edit ; .compile ; .run. Veya d1.search(filename='*.c' string='int \*'). Ya p1.stop, p1.bg. Bu benim ooshell anlayışım.


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


}

sadece referanslara dayanarak basa oo kavramlarını tanıtmayı denedim. 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

Kısa cevap için üzgünüm ama işte.

hipersayanx, Bash'te Object Oriented Programming adlı bir makale hazırladı . Temelde o hi-Jacked $FUNCNAME, function, compgenve exportbir bash alabilirsiniz OOP yakın olarak oluşturun.

Harika kısmı iyi çalışıyor ve bir sınıf oluşturmak için sadece birkaç kazan boru hattına ihtiyaç duyuyor.

Gerekli temel parçalar:

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

Kullanımı:

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

$instanceName_method

Şimdi, bunu AuditOps projemde kendim kullandım ve hipersayanx, bunun gerçekte sitesinde nasıl çalıştığı hakkında daha fazla ayrıntıya sahip. Bu çok bashism olmasına rağmen fare uyarısı, bash 4.0'dan daha eski herhangi bir şeyle çalışmaz ve hata ayıklamada baş ağrısına neden olabilir. Şahsen ben kazan kaplamanın çoğunun sınıfın kendisi olarak reddedildiğini görmek isterim.

Projenize daha uygun olduğunda, perl, ruby ​​ve python gibi ciddi bir OOP kodlama dili kullanmak her zaman akıllıca olacaktır. Ancak dürüst seçeneğimde, bu OOP yöntemini bash'te kullanmak için modüler bash scriptlerini tutarken zaman ve çabaya değer.


0

GitHub'da , HashMap Nesnesi , shell_map gibi çalışan bir fonksiyon geliştiriyorum .

" HashMap örnekleri " oluşturmak için bu işlev farklı adlar altında kendi kopyalarını oluşturabilir. Her yeni fonksiyon kopyası farklı bir $ FUNCNAME değişkenine sahip olacaktır. $ FUNCNAME, daha sonra her bir Map örneği için bir ad alanı oluşturmak için kullanılır.

Harita anahtarları, $ FUNCNAME_DATA_ $ KEY biçimindeki genel değişkenlerdir; burada $ KEY, Haritaya eklenen anahtardır. Bu değişkenler dinamik değişkenlerdir .

Körük basitleştirilmiş bir sürümünü koyacağım, böylece örnek olarak kullanabilirsiniz.

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

Kullanımı:

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

Komut ikame işleminin nasıl çalıştığını yanlış anlamış gibisiniz. Bu, backticks içinde yer alan komutun çıktısıyla değiştirilir, dönüş durumu ile değiştirilmez . Başka bir deyişle, kodunuz düşündüğünüzü yapmaz.
Wildcard

Aha. Haklısın. Özür dilerim. Ancak, bunun carp "Some error message"; returnyerine kullanmak çok daha net olacaktır .
Wildcard

Veya [ -z "$KEY" ] && { carp "some message"; return;} Alt kabuğa gerek yok. Ama aslında bu, bir if ... elif ... elif ... else ... fiyapı için gerçek bir aday gibi görünüyor - ki bu genellikle en iyi seçenek değil, ama muhtemelen burada. :) (Ya da belki bir dava anahtarı.)
Joker 21

@Wildcard Ben cevabı düzenledi. Şimdi sazan ve sırt çubukları hakkındaki tartışmamızın bir anlamı yok. bu sohbeti silelim mi?
Bruno Negrão Zica

0

Plumbum , Python benzeri bir kabuk dilidir. Deneyimi nesne yönelimli hale getirerek Python ile kabuk gibi bir sözdizimi oluşturur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.