* nix를위한 객체 지향 쉘


38

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

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

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

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


3
있다 PASH는 하지만 훨씬 더 배쉬 같은보다 파워 쉘-같다.
ephemient

1
@ephemient 어쩌면 pash에 대한 답을 써야 할 것입니다 ...하지만 아무것도 알지 못하지만 iirc, powershell은 OO 쉘입니다.
xenoterracide

4
야, 당신은 ipython을 확인해야합니다 . 파이썬으로 이해가되지 않는 표현식을 입력하면, 쉘 명령에 매핑을 시도합니다. 예를 들어, 물건처럼 cd ~다음 ls배쉬에서와 같이 작동합니다. 와 같은 명령을 사용하여 출력을 파이썬 변수 (행 목록 ... 종류)에 할당 할 수도 있습니다 listing = !ls.
직관

@intuited : 굉장하다, 나는 그것을 확인할 것이다
Robert S Ciaccio

1
@intuited : iPython은 내가하고 싶은 일에 꽤 좋았습니다. 감사합니다!
Robert S Ciaccio

답변:


43

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

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

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

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

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

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

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

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


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

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

  • irb (대화 형 루비) 는 Python 콘솔에 해당하는 Ruby입니다.

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

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

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


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

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

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


1
"이것이 당신이 쫓아 온 것 같아"라고 말한 직후 머리에 못을 박았다. 내가이 질문을하는 주된 이유는 유닉스 도구의 힘을 좋아하지만 프로그램 간의 텍스트 기반 상호 작용은 분명히 '더 복잡한 작업의 장벽을 제기'한다는 것입니다. 나는 텍스트 파서를 작성하는 데 프로그래밍 일을 충분히 보냈다 :) 나는 이것이 매우 잘 생각되는 답변이라고 생각한다. 그것은 문제의 핵심과 주제의 복잡성에 도달합니다. 나는 두 번 upvote에 수 소원 : P
로버트 S Ciaccio

1
OP가 무엇을 원하는지 전혀 모르겠지만 ipython의 경우 +1입니다.
Falmarri

1
이것은 정답입니다. 저는 재미있는 박사 학위 논문의 씨앗이 여기 있다고 생각합니다.
Ziggy

1
@RobertSCiaccio이 답변은 최근 게시물에 링크되어 있으며 텍스트 구문 분석에 대한 귀하의 의견은 저를 생각하게했습니다 ... 텍스트 구문 분석이 "복잡한 작업"을 수행하기에 충분하다면 작은 스크립트 나 프로그램을 구현할 수 없었습니다. 그것을 bash 스크립트에서 일종의 기능으로 사용합니까? 내 생각에, 나는 내 벨트 아래에서 말할 수있는 많은 bash 스크립팅 경험이 없다.
Oxwivi

1
@onlyanegg 물고기는 어떤 방식으로“객체 지향”이라고 말할 수 있습니까? 물고기는 주로 더 단순 해지는 것을 목표로합니다. 대안보다 더 강력한 방법이 있습니까?
Gilles 'SO- 악마 그만'

13

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 "$@" "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

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

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을위한 것이 아닙니다 . 쉘 루프를 사용하여 텍스트를 처리하지 않는 이유, 특히 C와 같은 언어의 목적 차이를 자세히 설명하는 "개념적으로"라는 섹션에 대한 Stephane의 답변을 상기시킵니다 bash. unix.stackexchange.com/a/169765/135943
와일드 카드

1
작동할까요? 그것은 효과가 있지만, 요점은 잘못은 아니지만 완료되지 않았다는 것입니다. 나는 또한 OP 질문에 대답하지 않았지만 bash가 TC라면 객체를 처리 할 수 ​​있어야한다고 생각했습니다. 그리고 많은 사람들이 이것을 증명했습니다.
Philcolbourn


5

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

표준 쉘 기능 : 작업 제어, readline 편집 및 히스토리, 별명 cat ls cdpwd, 호출기 통합, python 변수에 지정할 !수있는 %rehashx, 명령 출력 및 쉘 변수로 사용 가능한 python 값 을 앞에 붙여서 시스템 명령을 실행합니다 .

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

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




2

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

다른 답변에 제공된 기본 예제 중 하나를 따르지만이 구문으로 예제를 사용하여 답변을 업데이트하고 있습니다. 예제 프로그램은 비슷하지만 모든 변수 앞에 클래스 이름을 붙일 필요는 없습니다 (이것은 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"라는 텍스트를 표시한다고 가정 해 봅시다. 먼저 텍스트를 표시 할 속성이 있고이 텍스트를 설정하고 표시하는 메서드가있는 객체 클래스를 만듭니다. 클래스의 여러 인스턴스가 함께 작동하는 방법을 보여주기 위해 텍스트를 표시하는 두 가지 방법을 추가했습니다. 하나는 끝에 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

이것은 파이썬을 기반으로 한 객체 지향 쉘이지만 Golang에 가까운 sintaxe가 있습니다 : 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.stop, p1.bg. 그것이 우쉘에 대한 나의 이해입니다.


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을 기반으로 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

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

hipersayanx는 Bash에서 Object Oriented Programming 기사를 작성했습니다 . 기본적으로 그는 하이 자켓이 $FUNCNAME, function, compgen, 그리고 export하나의 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보다 오래된 것은 작동하지 않으며 디버깅에 두통을 일으킬 수 있습니다. 개인적으로 나는 보일러 도금의 대부분을 클래스 자체로 다시 만들고 싶습니다.

프로젝트에 더 적합 할 때 펄, 루비 및 파이썬과 같은 심각한 OOP 스크립팅 언어를 사용하는 것이 항상 더 현명합니다. 그러나 솔직히 옵션으로 모듈 식 bash 스크립트를 유지 관리 할 때 시간과 노력이 가치가 있습니다 .bash 에서이 OOP 방법을 활용하십시오.


0

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

명령 대체가 어떻게 작동하는지 오해 한 것 같습니다. 백틱에 포함 된 명령 의 출력 으로 대체되며 return status 로 대체되지 않습니다 . 다시 말해, 코드는 생각한대로 작동하지 않습니다.
와일드 카드

아하. 당신이 올바른지. 사과드립니다. 그러나 carp "Some error message"; return대신 사용 하는 것이 훨씬 명확합니다 .
와일드 카드

또는 [ -z "$KEY" ] && { carp "some message"; return;} 서브 쉘이 필요하지 않습니다. 그러나 실제로는 if ... elif ... elif ... else ... fi구성에 대한 실제 후보처럼 보입니다. 종종 최선의 선택은 아니지만 아마도 여기에 있습니다. :) (또는 아마도 스위치 일 수도 있습니다.)
Wildcard

@Wildcard 나는 대답을 편집했다. 잉어와 백틱에 대한 우리의 논의는 의미가 없습니다. 이 대화를 삭제하겠습니까?
Bruno Negrão Zica 2016 년

0

Plumbum 은 Python과 유사한 셸 언어입니다. Python을 사용하여 쉘과 같은 구문을 패키지화하여 경험을 객체 지향으로 만듭니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.