it-swarm-ko.tech

* nix를위한 객체 지향 쉘

머리말 : 나는 bash를 좋아하고 어떤 종류의 논쟁이나 성전을 시작할 의도가 없으며, 이것이 매우 순진한 질문이 아니길 바랍니다.

이 질문은 수퍼 유저의 이 게시물 과 관련이 있지만 OP가 실제로 자신이 요구하는 것을 알지 못했다고 생각합니다. FreeBSD, linux, OS X 및 Windows의 cygwin에서 bash를 사용합니다. 또한 Windows의 PowerShell에서 최근에 광범위한 경험을 가지고 있습니다.

Bash와 호환되지만 객체 지향 스크립팅 계층을 믹스에 추가하는 * nix 용 쉘 (이미 사용 가능하거나 작업중인 것)이 있습니까? 내가 아는 유일한 것은 python 콘솔이지만, 내가 말할 수있는 한 표준 Shell 환경에 대한 액세스를 제공하지는 않습니다. 예를 들어 python 콘솔에서 cd ~ls, chmod +x file만으로는 할 수 없습니다. 표준 유닉스 바이너리 대신 이러한 작업을 수행하려면 python을 사용하거나 python 코드를 사용하여 바이너리를 호출해야합니다.

그러한 껍질이 존재합니까?

42
Robert S Ciaccio

셸에서 세 가지 바람직한 기능을 생각할 수 있습니다.

  • 대화식 유용성 : 일반적인 명령은 빠르게 입력해야합니다. 완성; ...
  • 프로그래밍 : 데이터 구조; 동시성 (작업, 파이프 등); ...
  • 시스템 액세스 : 파일, 프로세스, 창, 데이터베이스, 시스템 구성 작업 ...

유닉스 쉘은 대화식 측면에 집중하는 경향이 있으며 대부분의 시스템 액세스 및 다음과 같은 외부 도구에 대한 일부 프로그래밍을 하도급합니다.

  • 간단한 수학의 경우 bc
  • 암호화의 경우 openssl
  • sed , awk 및 기타 텍스트 처리
  • 기본 TCP/IP 네트워킹의 경우 nc
  • FTP의 경우 ftp
  • 기본 이메일의 경우 mail, Mail, mailx
  • 예약 된 작업의 경우 cron
  • 기본 X 윈도우 조작의 경우 wmctrl
  • KDE ≤3.x 라이브러리의 경우 dcop
  • dbus 도구 (dbus-* 또는 qdbus ) 다양한 시스템 정보 및 구성 작업 (KDE ≥4와 같은 최신 데스크탑 환경 포함)

올바른 인수 또는 파이프 입력을 사용하여 명령을 호출하면 많은 작업을 수행 할 수 있습니다. 이 방법은 매우 강력합니다. 모든 작업을 잘못 수행하는 단일 프로그램보다 작업 당 하나의 도구를 사용하는 것이 좋습니다. 그러나 그 한계는 있습니다.

유닉스 쉘의 주요 한계는 이것이 "객체 지향 스크립팅"요구 사항을 따르는 것으로 생각됩니다. 한 명령에서 다른 명령으로 정보를 유지하거나 명령을 더 멋진 방식으로 결합하는 것이 좋지 않다는 것입니다. 파이프 라인. 특히 프로그램 간 통신은 텍스트 기반이므로 응용 프로그램은 호환 가능한 방식으로 데이터를 직렬화하는 경우에만 결합 할 수 있습니다. 이것은 축복이자 저주입니다. 모든 텍스트 접근 방식을 사용하면 간단한 작업을 빠르게 수행 할 수 있지만보다 복잡한 작업에 대한 장벽이 높아집니다.

대화식 유용성은 프로그램 유지 관리와는 반대로 실행됩니다. 대화 형 프로그램은 짧고 인용 부호가 적어야하며 변수 선언이나 타이핑 등으로 귀찮게하지 않아야합니다. 유지 관리 가능한 프로그램은 읽을 수 있어야하며 (약어가 많지 않아야 함) 읽을 수 있어야합니다. 문자열, 함수 이름, 변수 이름 등)이며 변수 선언 및 입력 등과 같은 일관성 검사가 있어야합니다.

요약하면 셸은 도달하기 어려운 절충안입니다. 자, 이것은 예에서 rant 섹션을 끝냅니다.


  • Perl Shell (psh) “Unix Shell의 대화 형 특성을 Perl의 힘과 결합합니다.” 간단한 명령 (파이프 라인도 포함)을 쉘 구문으로 입력 할 수 있습니다. 다른 모든 것은 Perl입니다. 이 프로젝트는 오랫동안 개발되지 않았습니다. 사용할 수는 있지만 순수한 Perl (스크립팅) 또는 순수한 셸 (대화식 또는 스크립팅)을 통해 사용하려고 생각하는 시점에 도달하지 못했습니다.

  • IPython 향상된 대화식 Python 콘솔, 특히 수치 및 병렬 컴퓨팅을 대상으로 함)입니다. 이것은 비교적 젊은 프로젝트입니다.

  • irb (interactive Ruby) Ruby Python 콘솔.

  • scsh 유닉스 셸 (문자열)에서 전통적으로 발견 된 시스템 바인딩 종류를 가진 체계 구현 (예 : 괜찮은 프로그래밍 언어) , 프로세스, 파일). 그러나 대화식 셸로 사용할 수는 없습니다.

  • zsh 는 향상된 대화식 셸입니다. 그 강점은 대화 형 기능 (명령 줄 판, 완성, 간결하지만 암호 구문으로 수행되는 일반적인 작업)입니다. 프로그래밍 기능은 크지 않지만 (ksh와 동등) 터미널 제어, 정규 표현식, 네트워킹 등을위한 많은 라이브러리가 제공됩니다.

  • fish 는 유닉스 스타일 쉘에서 깔끔한 시작입니다. 더 나은 프로그래밍 또는 시스템 액세스 기능이 없습니다. sh와의 호환성을 깨뜨리기 때문에 더 나은 기능을 발전시킬 여지가 더 많지만 아직 일어나지 않았습니다.


부록 : 유닉스 툴박스의 또 다른 부분은 많은 것을 파일로 취급하는 것입니다.

  • 대부분의 하드웨어 장치는 파일로 액세스 할 수 있습니다.
  • Linux에서 /sys는 더 많은 하드웨어 및 시스템 제어를 제공합니다.
  • 많은 유닉스 변형에서 프로세스 제어는 /proc 파일 시스템.
  • Fuse 새 파일 시스템을 쉽게 작성할 수 있습니다. 파일 형식을 즉시 변환하고, 다양한 네트워크 프로토콜을 통해 파일에 액세스하고, 아카이브 내부를 찾는 등의 파일 시스템이 이미 존재합니다.

어쩌면 유닉스 쉘의 미래는 명령을 통한 더 나은 시스템 액세스 (및 명령을 결합하는 더 나은 제어 구조)가 아니라 파일 시스템을 통한 더 나은 시스템 액세스 (약간 다르게 결합 됨)-핵심 관용구 (예 : 쉘 파이프))).

Bash에서 클래스 또는 객체를 구현하기 위해 많은 bash 코드가 필요하지 않습니다.

100 줄이라고하자.

Bash에는 상속, 메서드 및 속성을 사용하여 간단한 Object 시스템을 구현하는 데 사용할 수있는 연관 배열이 있습니다.

따라서 다음과 같은 클래스를 정의 할 수 있습니다.

class Queue N=10 add=q_add remove=q_remove

이 큐의 인스턴스 작성은 다음과 같이 수행 될 수 있습니다.

class Q:Queue N=100

또는

inst Q:Queue N=100

클래스는 배열로 구현되므로 classinst는 실제로 동의어입니다.

이 대기열에 항목을 추가하는 방법은 다음과 같습니다.

$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 "[email protected]" "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 "[email protected]"
}

단점은 데이터에 [0]을 사용할 수 없으므로 큐 (이 경우)가 index = 1에서 시작한다는 것입니다. 또는 "q + 0"과 같은 연관 인덱스를 사용할 수 있습니다.

getset 멤버에게는 다음과 같이 할 수 있습니다.

# basic set and get for key-value members
ROOT_set(){                                       # $QOBJ set key=value
    local _this=$1 _exp _key _val
    shift
    for _exp in "[email protected]"; 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 "[email protected]"; do
        _var=${_exp%%=*}
        _key=${_exp#*=}
        eval $_var=\"\${$_this[$_key]}\"
    done
}

그리고 dump 객체 구조로, 나는 이것을 만들었습니다.

참고 : 이것은 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
}

My OOP 디자인은 상속 된 클래스를 제외하고 개체 내의 개체를 고려하지 않았습니다. 개별적으로 만들거나 class ()와 같은 특수 생성자를 만들 수 있습니다. * obj_dump *는 감지하도록 수정해야합니다. 내부 클래스를 재귀 적으로 인쇄합니다.

오! class 함수를 단순화하기 위해 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

일부 큐 인스턴스를 작성하고 작동하게했습니다.

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 +는 bourne/posix Shell 구문을 유지하면서 일부 OO 개념을 소개합니다. http://blog.fpmurphy.com/2010/05/ksh93-using-types-to- create-object-orientated-scripts.html

7
jlliagre

IPython 놀랍게도 사용하기 편리합니다.

표준 쉘 기능 : 작업 제어, 리드 라인 편집 및 히스토리, 별명, catlscdpwd, 호출기 통합, 접두어로 시스템 명령 실행 ! 또는 %rehashx를 활성화하면 python 변수, python 쉘 변수로 사용 가능한 값)에 할당 할 수있는 명령 출력이 있습니다.

Python 전용 : 마지막 명령의 결과 재사용, 설명서 및 소스에 대한 빠른 액세스, 모듈 재로드, 디버거 당신이 그것에 있다면 일부 클러스터 지원.

즉, 복잡한 파이프를 실행하는 것은 Python에서 수행되지 않습니다. posix Shell을 사용할 것입니다. 접착제를 사용하여 값을 전달할 수 있습니다.

5
Tobu

이것은 사용 및 설정이 조금 더 간단하고 이름이 args 등입니다. https://github.com/uudruid74/bashTheObjects

다른 답변에 제공된 기본 예제 중 하나를 따르지만이 구문으로 예제를 사용하여 답변을 업데이트하고 있습니다. 예제 프로그램은 비슷하지만 모든 변수 앞에 클래스 이름을 붙일 필요는 없습니다 ( kindof 메소드로 알 수 있습니다) 구문이 much 더 간단하다고 생각하십시오!

먼저, 클래스 파일. 인스턴스 변수의 기본값은 선택 사항이며 생성자에 이러한 값을 전달하지 않은 경우에만 사용됩니다.

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 를 기다리지 않고 주어진 지점에서 클래스를 강제로로드합니다. 적절한 순서로 물건. 여러 인스턴스 변수를 한 번에 쉽게 설정할 수 있습니다.

디버그 레벨, 생성자, 소멸자, subclassing 및 기본 reflection 시스템도 있으며 print/println = echo를 대체합니다 (대시로 시작하는 변수를 인쇄하려고합니까?). github의 예제는 클래스에서 HTML을 생성하는 CGI로 실행되는 것을 보여줍니다.

라이브러리 자체 (oop.lib.sh)는 그렇게 단순하지 않지만 (400+ 라인, 11K), 라이브러리를 포함하고 잊어 버리면됩니다.

2
Evan Langlois

Ruby 및 Psh 를 사용하는 Rush 가 있으며 Perl을 기반으로합니다.

2
OneOfOne

Linux에서 PowerShell Core Edition 을 설치할 수 있습니다. Microsoft에서 활발하게 개발하고있는 크로스 플랫폼 .NET Core 프레임 워크에서 실행됩니다.

2
Trevor Sullivan

jq 이러한 종류의 객체 지향 레이어처럼 잘 작동합니다.

2
Abbafei

이것은 파이썬을 기반으로 한 객체 지향 쉘이지만 Golang과 가까운 sintaxe를 가지고 있습니다 : https://github.com/alexst07/Shell-plus-plus

예를 들어 catch를 시도하십시오.

try {
  git clone [email protected]: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} | [email protected]{cgrep} # pass an array to command
1
Alex

누군가가 객체 지향 프로그래밍 (속성 및 메소드)의 기본 사항 만 원한다면 정말 간단한 프레임 워크가 트릭을 수행합니다.

개체를 사용하여 "Hello World"라는 텍스트를 표시한다고 가정 해 봅시다. 먼저 텍스트를 표시 할 속성이 있고이 텍스트를 설정하고 표시하는 메서드가있는 객체 클래스를 만듭니다. 클래스의 여러 인스턴스가 함께 작동하는 방법을 보여주기 위해 텍스트를 표시하는 두 가지 방법을 추가했습니다. 하나는 끝에 NewLine이고 다른 하나는 그렇지 않습니다.

클래스 정의 파일 : 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"
}

이제 클래스 정의 파일과 "<<InstanceName>>"텍스트를 원하는 이름으로 바꾸어이 파일의 복사본을 만드는 CreateObject 함수가 있습니다.

HelloWorld.sh라는 스크립트에서 새 객체를 사용합시다 (HelloWorld.sh는 실행 가능해야합니다. 다른 두 파일은 필요하지 않습니다)

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


}

참조 http://hipersayanx.blogspot.in/2012/12/object-oriented-programming-in-bash.html 을 기반으로 bash에 oo 개념을 도입하려고했습니다.

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 은 파이썬과 유사한 셸 언어입니다. Python 경험을 객체 지향으로 만드는) 구문과 같은 쉘을 패키지합니다.

0
joshlk

이제 쉘에서 어떤 객체를 다루고 있습니까? 파일/디렉토리, 프로세스 및 상호 작용입니다. 따라서 f1.edit 또는 currentFile=f1.c ; .edit ; .compile ; .run와 같은 형식이어야합니다. 또는 d1.search(filename='*.c' string='int \*'). 또는 p1.stop, p1.bg. 그것이 우쉘에 대한 나의 이해입니다.

0
ott--

짧은 답변에 대해 죄송하지만 여기에갑니다.

hipersayanx는 기사 Bash의 객체 지향 프로그래밍 을 작성했습니다. 기본적으로 그는 $FUNCNAME, function, compgenexport OOP에 가까워지면 bash에 들어갈 수 있음).

멋진 부분은 잘 작동하고 클래스를 만들기 위해 보일러 라인 몇 줄만 있으면된다는 것입니다.

필요한 기본 부품은 다음과 같습니다.

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 및 OOP와 같은 스크립트 언어를 프로젝트에 더 잘 맞출 때와 같이 진지한 python 스크립팅 언어)를 사용하는 것이 더 현명합니다. bash에서 OOP)의이 방법을 사용하기 위해 모듈 식 bash 스크립트를 유지 보수 할 때의 시간과 노력.

0
Dwight Spencer

GitHub에서 HashMap Object , 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!"
0