Shell hướng đối tượng cho * nix


38

Lời nói đầu: Tôi thích bash và không có ý định bắt đầu bất kỳ cuộc tranh luận hay cuộc chiến tranh thần thánh nào, và hy vọng đây không phải là một câu hỏi cực kỳ ngây thơ.

Câu hỏi này có phần liên quan đến bài đăng này trên superuser, nhưng tôi không nghĩ OP thực sự biết những gì anh ấy yêu cầu. Tôi sử dụng bash trên FreeBSD, linux, OS X và cygwin trên Windows. Gần đây tôi cũng đã có nhiều kinh nghiệm với PowerShell trên Windows.

Có một vỏ cho * nix, đã có sẵn hoặc trong các tác phẩm, tương thích với bash nhưng thêm một lớp kịch bản hướng đối tượng vào hỗn hợp? Điều duy nhất tôi biết đến gần đó là giao diện điều khiển python, nhưng theo như tôi có thể nói nó không cung cấp quyền truy cập vào môi trường shell tiêu chuẩn. Ví dụ, tôi không thể cd ~lssau đó, chmod +x filetrong bảng điều khiển python. Tôi sẽ phải sử dụng python để thực hiện các tác vụ đó thay vì các nhị phân unix tiêu chuẩn hoặc gọi các nhị phân sử dụng mã python.

Liệu một cái vỏ như vậy có tồn tại?


3
Pash nhưng giống Powershell hơn nhiều so với Bash.
ephemient

1
@ephemient có lẽ bạn nên viết một câu trả lời cho pash ... mặc dù tôi không biết gì về nó, iirc, powershell là một vỏ OO.
xenoterracide

4
Này, bạn nên kiểm tra ipython . Nếu bạn nhập một biểu thức không có ý nghĩa như python, nó sẽ cố ánh xạ nó tới lệnh shell. Ví dụ, những thứ như cd ~tiếp theo là lshoạt động như trong Bash. Bạn cũng có thể gán đầu ra cho các biến Python (danh sách các dòng. Sắp xếp) với các lệnh như listing = !ls.
trực giác

@intuited: tuyệt vời, tôi sẽ xem thử
Robert S Ciaccio

1
@intuited: iPython đã khá tốt cho những thứ tôi muốn làm, cảm ơn!
Robert S Ciaccio

Câu trả lời:


43

Tôi có thể nghĩ về ba tính năng mong muốn trong một vỏ:

  • Khả năng tương tác: các lệnh phổ biến nên nhanh chóng gõ; hoàn thành; ...
  • Lập trình: cấu trúc dữ liệu; đồng thời (công việc, đường ống, ...); ...
  • Truy cập hệ thống: làm việc với các tệp, quy trình, cửa sổ, cơ sở dữ liệu, cấu hình hệ thống, ...

Các shell Unix có xu hướng tập trung vào khía cạnh tương tác và hợp đồng phụ hầu hết quyền truy cập hệ thống và một số chương trình cho các công cụ bên ngoài, chẳng hạn như:

  • bc cho toán đơn giản
  • openssl cho mật mã
  • sed , awk và những người khác để xử lý văn bản
  • nc cho mạng TCP / IP cơ bản
  • ftp cho FTP
  • mail, Mail, mailx, Vv cho e-mail cơ bản
  • cron cho các nhiệm vụ theo lịch trình
  • wmctrl cho thao tác cửa sổ X cơ bản
  • dcop cho các thư viện KDE ≤3.x
  • các công cụ dbus ( dbus-*hoặc qdbus ) cho các tác vụ cấu hình và thông tin hệ thống khác nhau (bao gồm cả các môi trường máy tính để bàn hiện đại như KDE 4)

Nhiều, nhiều điều có thể được thực hiện bằng cách gọi một lệnh với các đối số hoặc đầu vào đúng. Đây là một cách tiếp cận rất mạnh mẽ - tốt hơn là có một công cụ cho mỗi nhiệm vụ thực hiện tốt, hơn là một chương trình duy nhất làm mọi thứ nhưng không tốt - nhưng nó có những hạn chế.

Một hạn chế lớn của shell unix và tôi nghi ngờ đây là những gì bạn đang có với yêu cầu kịch bản hướng đối tượng của bạn, là chúng không giữ được thông tin từ lệnh này sang lệnh tiếp theo hoặc kết hợp các lệnh theo cách dễ hiểu hơn một đường ống dẫn. Cụ thể, giao tiếp giữa các chương trình dựa trên văn bản, vì vậy các ứng dụng chỉ có thể được kết hợp nếu chúng tuần tự hóa dữ liệu của chúng theo cách tương thích. Đây vừa là một phước lành vừa là một lời nguyền: cách tiếp cận mọi thứ là văn bản giúp bạn dễ dàng hoàn thành các nhiệm vụ đơn giản một cách nhanh chóng, nhưng làm tăng rào cản cho các nhiệm vụ phức tạp hơn.

Khả năng sử dụng tương tác cũng chạy thay vì khả năng bảo trì chương trình. Các chương trình tương tác nên ngắn gọn, yêu cầu trích dẫn ít, không làm phiền bạn với các khai báo biến hoặc gõ, v.v. Các chương trình duy trì nên có thể đọc được (vì vậy không có nhiều chữ viết tắt), nên có thể đọc được (vì vậy bạn không phải tự hỏi liệu một từ trần là một chuỗi, một tên hàm, một tên biến, v.v.), nên có các kiểm tra tính nhất quán như khai báo biến và gõ, v.v.

Tóm lại, một cái vỏ là một sự thỏa hiệp khó đạt được. Ok, điều này kết thúc phần rant, trên các ví dụ.


  • Các Perl Shell (PSH) “kết hợp các chất tương tác của một vỏ Unix với sức mạnh của Perl”. Các lệnh đơn giản (thậm chí các đường ống) có thể được nhập theo cú pháp shell; mọi thứ khác là Perl. Dự án đã không được phát triển trong một thời gian dài. Nó có thể sử dụng được, nhưng chưa đạt đến điểm mà tôi xem xét sử dụng nó trên Perl thuần túy (để viết kịch bản) hoặc shell thuần (tương tác hoặc cho kịch bản).

  • IPython là một giao diện điều khiển Python tương tác được cải tiến, đặc biệt được nhắm mục tiêu ở tính toán số và song song. Đây là một dự án tương đối trẻ.

  • irb (ruby tương tác) là tương đương với Ruby của bảng điều khiển Python.

  • scsh là một triển khai lược đồ (tức là một ngôn ngữ lập trình đàng hoàng) với các loại ràng buộc hệ thống thường được tìm thấy trong các vỏ unix (chuỗi, quy trình, tệp). Tuy nhiên, nó không nhằm mục đích có thể sử dụng như một vỏ tương tác.

  • zsh là một vỏ tương tác được cải thiện. Điểm mạnh của nó là tính tương tác (phiên bản dòng lệnh, hoàn thành, các tác vụ phổ biến được thực hiện với cú pháp ngắn gọn nhưng khó hiểu). Các tính năng lập trình của nó không tuyệt vời (ngang bằng với ksh), nhưng nó đi kèm với một số thư viện để điều khiển thiết bị đầu cuối, biểu thức chính quy, kết nối mạng, v.v.

  • là một khởi đầu sạch ở vỏ kiểu unix. Nó không có tính năng truy cập hệ thống hoặc lập trình tốt hơn. Bởi vì nó phá vỡ tính tương thích với sh, nó có nhiều chỗ hơn để phát triển các tính năng tốt hơn, nhưng điều đó đã không xảy ra.


Phụ lục: một phần khác của hộp công cụ unix đang xử lý nhiều thứ dưới dạng tệp:

  • Hầu hết các thiết bị phần cứng có thể truy cập dưới dạng tập tin.
  • Trong Linux, /syscung cấp thêm phần cứng và kiểm soát hệ thống.
  • Trên nhiều biến thể unix, điều khiển quá trình có thể được thực hiện thông qua /prochệ thống tập tin.
  • FUSE giúp dễ dàng viết các hệ thống tập tin mới. Hiện đã có các hệ thống tệp hiện có để chuyển đổi định dạng tệp một cách nhanh chóng, truy cập các tệp qua các giao thức mạng khác nhau, xem bên trong kho lưu trữ, v.v.

Có thể tương lai của shell unix không phải là truy cập hệ thống tốt hơn thông qua các lệnh (và các cấu trúc điều khiển tốt hơn để kết hợp các lệnh) mà là truy cập hệ thống tốt hơn thông qua các hệ thống tệp (kết hợp hơi khác nhau - Tôi không nghĩ chúng ta đã tìm ra những thành ngữ chính nào (như ống vỏ) chưa).


1
Bạn đánh vào đầu đinh ngay sau khi bạn nói "Tôi nghi ngờ đây là thứ bạn đang theo đuổi". Lý do chính tôi đặt câu hỏi này là tôi thích có sức mạnh của các công cụ unix, nhưng sự tương tác dựa trên văn bản giữa các chương trình chắc chắn 'tạo ra rào cản cho các nhiệm vụ phức tạp hơn'. Tôi đã dành đủ thời gian lập trình để viết trình phân tích cú pháp văn bản :) Tôi nghĩ rằng đây là một câu trả lời được suy nghĩ rất kỹ. Nó đi vào trọng tâm của vấn đề và sự phức tạp của chủ đề. Tôi ước tôi có thể nâng cấp nó hai lần: P
Robert S Ciaccio

1
+1 cho ipython, mặc dù tôi không biết OP muốn làm gì.
Falmarri

1
Đây là một câu trả lời tuyệt vời: Tôi thành thật nghĩ rằng hạt giống của một luận án tiến sĩ thú vị đang ở đây.
Ziggy

1
@RobertSCiaccio Câu trả lời này chỉ được liên kết trong một bài đăng gần đây và nhận xét của bạn về phân tích văn bản khiến tôi suy nghĩ ... nếu phân tích văn bản là đủ để thực hiện "các nhiệm vụ phức tạp" của bạn, thì bạn không thể có một kịch bản hoặc chương trình nhỏ thực hiện nó và sử dụng nó như một loại chức năng trong tập lệnh bash của bạn? Chỉ cần một suy nghĩ, tôi không có nhiều kinh nghiệm viết kịch bản dưới vành đai của mình để nói về.
Oxwivi

1
@onlyanegg Theo cách nào thì cá có thể được gọi là hướng đối tượng của người Hồi giáo? Cá chủ yếu nhằm mục đích đơn giản hơn. Có cách nào mạnh hơn giải pháp thay thế không?
Gilles 'SO- ngừng trở nên xấu xa'

13

Bạn không cần nhiều mã bash để triển khai các lớp hoặc đối tượng trong bash.

Nói, 100 dòng.

Bash có các mảng kết hợp có thể được sử dụng để thực hiện một hệ thống Object đơn giản với sự kế thừa, phương thức và thuộc tính.

Vì vậy, bạn có thể định nghĩa một lớp như thế này:

class Queue N=10 add=q_add remove=q_remove

Tạo một thể hiện của Hàng đợi này có thể được thực hiện như thế này:

class Q:Queue N=100

hoặc là

inst Q:Queue N=100

Vì các lớp được triển khai với một mảng, lớpinst thực sự là từ đồng nghĩa - giống như trong javascript.

Thêm các mục vào hàng đợi này có thể được thực hiện như thế này:

$Q add 1 2 aaa bbb "a string"

Việc xóa các mục vào một biến X có thể được thực hiện như sau:

$Q remove X

Và cấu trúc bán phá giá của một đối tượng có thể được thực hiện như thế này:

$Q dump

Mà sẽ trả lại một cái gì đó như thế này:

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

Các lớp được tạo bằng hàm lớp như thế này:

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

LƯU Ý: Khi xác định một lớp hoặc thể hiện mới, bạn có thể ghi đè bất kỳ giá trị hoặc hàm thành viên nào.

Các mảng kết hợp Bash có một cách giải quyết giúp công việc này gọn gàng: $ Q [0]} giống hệt với $ Q. Điều này có nghĩa là chúng ta có thể sử dụng tên mảng để gọi hàm gửi phương thức:

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

Mặt trái là tôi không thể sử dụng [0] cho dữ liệu để hàng đợi của tôi (trong trường hợp này) bắt đầu từ index = 1. Ngoài ra, tôi có thể đã sử dụng các chỉ số kết hợp như "q + 0".

Để có đượcthiết lập thành viên, bạn có thể làm một cái gì đó như thế này:

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

Và để kết xuất một cấu trúc đối tượng, tôi đã thực hiện điều này:

LƯU Ý: Điều này không bắt buộc đối với OOP trong bash, nhưng thật tuyệt khi thấy các đối tượng được tạo ra như thế nào.

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

Thiết kế OOP của tôi đã không xem xét các đối tượng trong các đối tượng - ngoại trừ lớp kế thừa. Bạn có thể tạo chúng một cách riêng biệt hoặc tạo một hàm tạo đặc biệt như class (). * obj_dump * sẽ cần được sửa đổi để phát hiện các lớp bên trong để in đệ quy chúng.

Oh! và tôi tự định nghĩa một lớp ROOT để đơn giản hóa chức năng lớp :

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

Với một vài hàm hàng đợi, tôi đã định nghĩa một số lớp như thế này:

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

Tạo một số trường hợp Hàng đợi và làm cho chúng hoạt động:

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

Có thể làm việc nhưng nó xấu . Và hoàn toàn không phải bashlà những gì cho. Nhắc nhở tôi về câu trả lời của Stephane về lý do tại sao không sử dụng các vòng lặp shell để xử lý văn bản, đặc biệt là phần có tiêu đề "về mặt khái niệm", chi tiết về sự khác biệt về mục đích giữa các ngôn ngữ như C và bash. unix.stackexchange.com/a/169765/135943
tự đại diện

1
Có thể làm việc? Nó hoạt động, nhưng quan điểm của bạn là, mặc dù không sai, nhưng nó không được thực hiện. Tôi cũng không trả lời câu hỏi OP, nhưng nếu bash là TC thì tôi nghĩ nó sẽ có thể xử lý các đối tượng. Và nhiều người đã chứng minh điều này.
philcolbourn


5

IPython là thuận tiện đáng ngạc nhiên để sử dụng.

Các tính năng shell tiêu chuẩn: kiểm soát công việc, chỉnh sửa và đọc lịch sử, bí danh cat ls cdpwdtích hợp máy nhắn tin, chạy bất kỳ lệnh hệ thống nào bằng cách thêm tiền tố !hoặc bật %rehashx, lệnh đầu ra có thể gán cho biến python, giá trị python có sẵn dưới dạng biến shell.

Cụ thể của Python: sử dụng lại kết quả từ các lệnh cuối cùng, truy cập nhanh vào tài liệu và nguồn, tải lại mô-đun, trình gỡ lỗi. Một số hỗ trợ cụm nếu bạn vào đó.

Điều đó nói rằng, chạy các đường ống phức tạp không được thực hiện trong Python; bạn cũng sẽ sử dụng shell posix, chỉ với một ít keo để truyền các giá trị qua lại.



2

jq hoạt động khá tốt như một loại lớp hướng đối tượng.


2

Cái này đơn giản hơn một chút để sử dụng và thiết lập, đã đặt tên args, v.v ... https://github.com/uudruid74/bashTheObjects

Tôi đang cập nhật câu trả lời của mình bằng một ví dụ, theo một trong những ví dụ cơ bản được đưa ra cho câu trả lời khác, nhưng với cú pháp này. Chương trình ví dụ tương tự, nhưng bạn không cần phải thêm tiền tố vào tất cả các biến có tên lớp (nó biết đây là phương thức kindof hiển thị) và tôi nghĩ cú pháp đơn giản hơn nhiều !

Đầu tiên, một tập tin lớp. Mặc định cho các biến thể hiện là tùy chọn và chỉ được sử dụng nếu bạn không chuyển các giá trị này vào hàm tạo.

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
}

Bây giờ để sử dụng ví dụ:

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

GHI CHÚ:

  1. Điều đó khẳng định cuối cùng sẽ thất bại. Không giống như ví dụ trên, thư viện chưa hỗ trợ gán đối tượng, nhưng điều đó sẽ không quá khó để thêm vào. Tôi sẽ đặt nó trên TO-DO của mình cùng với hỗ trợ container / iterator sắp tới.

Báo cáo nhập khẩu về mặt kỹ thuật là không bắt buộc, nhưng nó buộc phải tải lớp tại điểm đã cho thay vì chờ đợi cái mới đầu tiên , có thể giúp khởi tạo mọi thứ theo thứ tự thích hợp. Lưu ý sự dễ dàng mà tại đó bạn có thể đặt nhiều biến đối tượng cùng một lúc.

Ngoài ra còn có các mức gỡ lỗi, hàm tạo, hàm hủy, phân lớp và hệ thống phản xạ cơ bản và được hiển thị là print / println để thay thế echo (bao giờ thử in một biến bắt đầu bằng dấu gạch ngang?). Ví dụ trên github cho thấy nó chạy dưới dạng CGI tạo HTML từ các lớp.

Bản thân thư viện (oop.lib.sh) không đơn giản như vậy (hơn 400 dòng, 11K), nhưng bạn chỉ cần đưa nó vào và quên nó đi.



1

Nếu ai đó chỉ muốn những điều cơ bản của lập trình hướng đối tượng (thuộc tính và phương thức) hơn là một khung thực sự đơn giản sẽ thực hiện thủ thuật.

Giả sử bạn muốn hiển thị văn bản "Hello World" bằng các đối tượng. Trước tiên, bạn tạo một lớp đối tượng có thuộc tính cho văn bản được hiển thị và có một số phương thức để đặt văn bản này và hiển thị nó. Để cho thấy có bao nhiêu phiên bản của một lớp có thể hoạt động cùng nhau, tôi đã thêm hai phương thức để hiển thị văn bản: một với NewLine ở cuối và một không có cái đó.

Tệp định nghĩa lớp: 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"
}

Vui lòng lưu ý từ "<InstanceName >>". Điều này sẽ được thay thế sau này để tạo nhiều thể hiện của một đối tượng lớp. Trước khi bạn có thể sử dụng một thể hiện của một đối tượng, bạn cần một hàm thực sự tạo ra nó. Để đơn giản, nó sẽ là một tập lệnh riêng gọi là: 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"
}

Vì vậy, bây giờ chúng ta có một tệp định nghĩa lớp và hàm CreatObject tạo ra một bản sao của tệp này với văn bản "<InstanceName >>" được thay thế bằng bất kỳ tên nào chúng ta muốn.

Hãy sử dụng đối tượng mới của chúng tôi trong một tập lệnh có tên: HelloWorld.sh (xin lưu ý rằng HelloWorld.sh nên được thực thi. Hai tệp khác không cần phải)

# 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

Bằng cách chạy tập lệnh HelloWorld.sh, nó sẽ hiển thị nội dung "Hello World" (và thêm NewLine). Không ai sẽ bị ấn tượng nhiều bởi kết quả này, tuy nhiên chúng ta sẽ biết điều này không đơn giản như vẻ ngoài của nó :)

Chúc mừng mã hóa!


Nó là tốt hơn để làm cho những điều phức tạp đơn giản hơn là làm cho những điều đơn giản trở nên phức tạp.
tự đại diện

1

Đây là một vỏ hướng đối tượng dựa trên Python, nhưng nó có một sintaxe gần với Golang: https://github.com/alexst07/shell-plus-plus

Ví dụ: thử bắt:

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

quá tải lớp và toán tử:

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)

và bạn có thể sử dụng các lệnh tương tự 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

Bây giờ, với những đối tượng mà bạn đang đối phó trong một vỏ hầu hết thời gian? Đó là tập tin / thư mục, quy trình và sự tương tác của chúng. Vì vậy, nó nên thích f1.edithoặc một cái gì đó như currentFile=f1.c ; .edit ; .compile ; .run. Hoặc d1.search(filename='*.c' string='int \*'). Hoặc p1.stop, p1.bg. Đó là sự hiểu biết của tôi về một 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


}

vừa thử giới thiệu oo khái niệm cho bash dựa trên tài liệu tham khảo 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

Xin lỗi vì trả lời ngắn nhưng ở đây đi.

hipersayanx đã tạo ra một bài viết Lập trình hướng đối tượng trong Bash . Về cơ bản, ông hi-jacked $FUNCNAME, function, compgen, và exportđể tạo ra càng gần OOP người ta có thể nhận được trong bash.

Phần thú vị là nó hoạt động tốt và người ta chỉ cần một vài dòng lò hơi để xây dựng một lớp.

Các bộ phận cơ bản cần có là:

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

Sử dụng:

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

$instanceName_method

Bây giờ, tôi đã sử dụng bản thân mình trong dự án AuditOps của mình và hipersayanx có thêm thông tin chi tiết về cách thức này thực sự hoạt động trên trang web của anh ấy. Cảnh báo giá vé mặc dù điều này rất bashism sẽ không hoạt động với bất cứ điều gì cũ hơn bash 4.0 và có thể dẫn đến đau đầu trong việc gỡ lỗi. Trong khi cá nhân tôi muốn thấy hầu hết các lò hơi mạ được làm lại như là một lớp học.

Luôn luôn khôn ngoan hơn khi sử dụng ngôn ngữ kịch bản OOP nghiêm túc như perl, ruby ​​và python khi phù hợp hơn với dự án của bạn. Tuy nhiên, trong tùy chọn trung thực của tôi, nó đáng giá thời gian và công sức khi duy trì các tập lệnh bash mô-đun để sử dụng phương pháp OOP này trong bash.


0

Tôi đang phát triển trên GitHub một chức năng hoạt động giống như Đối tượng HashMap , shell_map .

Để tạo " phiên bản HashMap ", chức năng này có thể tạo các bản sao của chính nó dưới các tên khác nhau. Mỗi bản sao chức năng mới sẽ có một biến $ FUNCNAME khác nhau. $ FUNCNAME sau đó được sử dụng để tạo một không gian tên cho mỗi phiên bản Map.

Các khóa bản đồ là các biến toàn cục, ở dạng $ FUNCNAME_DATA_ $ KEY, trong đó $ KEY là khóa được thêm vào Bản đồ. Các biến này là các biến động .

Dưới đây tôi sẽ đặt một phiên bản đơn giản hóa của nó để bạn có thể sử dụng làm ví dụ.

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

Sử dụng:

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

Bạn dường như đã hiểu sai về cách thay thế lệnh hoạt động. Nó được thay thế bằng đầu ra của lệnh chứa trong backticks, không được thay thế bằng trạng thái trả về . Nói cách khác, mã của bạn không làm những gì bạn nghĩ.
tự đại diện

Aha. Bạn nói đúng. Lời xin lỗi của tôi. Tuy nhiên, nó sẽ rõ ràng hơn để sử dụng carp "Some error message"; returnthay thế.
tự đại diện

Hoặc [ -z "$KEY" ] && { carp "some message"; return;} không cần cho một subshell. Nhưng thật ra, nó trông giống như một ứng cử viên thực sự cho một if ... elif ... elif ... else ... ficông trình xây dựng thường không phải là sự lựa chọn tốt nhất, nhưng có lẽ là ở đây. :) (Hoặc có thể là một trường hợp chuyển đổi.)
Wildcard

@Wildcard Tôi đã chỉnh sửa câu trả lời. Bây giờ thảo luận của chúng tôi về cá chép và backticks không có ý nghĩa. Hãy xóa cuộc trò chuyện này?
Bruno Negrão Zica

0

Plumbum là một ngôn ngữ shell giống như Python. Nó gói shell như cú pháp với Python làm cho trải nghiệm hướng đối tượng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.