서문 : 나는 bash를 좋아하고 어떤 종류의 논쟁이나 성전을 시작할 의도가 없으며, 이것이 매우 순진한 질문이 아니길 바랍니다.
이 질문은 수퍼 유저 관련 게시물 과 관련 이 있지만 OP가 실제로 요청한 내용을 알고 있다고 생각하지 않습니다. FreeBSD, linux, OS X 및 Windows의 cygwin에서 bash를 사용합니다. 또한 Windows의 PowerShell에서 최근에 광범위한 경험을 가지고 있습니다.
bash와 호환되지만 객체 지향 스크립팅 계층을 믹스에 추가하는 * nix 용 쉘이 이미 있거나 사용 가능합니까? 내가 아는 유일한 것은 파이썬 콘솔이지만, 내가 알 수있는 한 표준 쉘 환경에 액세스 할 수는 없습니다. 예를 들어, 나는 단지 수 cd ~
및 ls
다음 chmod +x file
파이썬 콘솔 내부. 표준 유닉스 바이너리 대신 이러한 작업을 수행하거나 파이썬 코드를 사용하여 바이너리를 호출하려면 파이썬을 사용해야합니다.
그러한 껍질이 존재합니까?
답변
쉘에서 세 가지 바람직한 기능을 생각할 수 있습니다.
- 대화식 유용성 : 일반적인 명령은 빠르게 입력해야합니다. 완성; …
- 프로그래밍 : 데이터 구조; 동시성 (작업, 파이프 등); …
- 시스템 액세스 : 파일, 프로세스, 창, 데이터베이스, 시스템 구성 작업 …
유닉스 쉘은 대화식 측면에 집중하는 경향이 있으며 대부분의 시스템 액세스 및 다음과 같은 외부 도구에 대한 일부 프로그래밍을 하도급합니다.
- 간단한 수학을위한 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를 사용하면 새 파일 시스템을 쉽게 작성할 수 있습니다. 파일 형식을 즉시 변환하고, 다양한 네트워크 프로토콜을 통해 파일에 액세스하고, 아카이브 내부를 보는 등의 파일 시스템이 이미 존재합니다.
어쩌면 유닉스 쉘의 미래는 명령을 통한 더 나은 시스템 액세스 (및 명령을 결합하는 더 나은 제어 구조)가 아니라 파일 시스템을 통한 더 나은 시스템 액세스 (약간 다르게 결합)-우리가 핵심 관용구 (예 : 쉘 파이프))).
답변
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
클래스는 배열로 구현되므로 class 와 inst 는 실제로 동의어입니다.
이 대기열에 항목을 추가하는 방법은 다음과 같습니다.
$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
답변
ksh93t +는 bourne / posix 쉘 구문을 유지하면서 일부 OO 개념을 소개합니다. http://blog.fpmurphy.com/2010/05/ksh93-using-types-to-create-object-orientated-scripts.html
답변
IPython 은 놀랍게도 사용하기 편리합니다.
표준 쉘 기능 : 작업 제어, readline 편집 및 히스토리, 별명 cat
ls
cd
및 pwd
, 호출기 통합, python 변수에 지정할 !
수있는 %rehashx
, 명령 출력 및 쉘 변수로 사용 가능한 python 값 을 앞에 붙여서 시스템 명령을 실행합니다 .
Python 전용 : 마지막 명령의 결과 재사용, 설명서 및 소스에 대한 빠른 액세스, 모듈 재로드, 디버거 당신이 그것에 있다면 일부 클러스터 지원.
즉, 복잡한 파이프를 실행하는 것은 Python에서 수행되지 않습니다. posix 쉘을 사용할 것입니다. 접착제를 사용하여 값을 전달할 수 있습니다.
답변
답변
jq
이런 종류의 객체 지향 레이어처럼 잘 작동합니다.
답변
이것은 사용 및 설정이 조금 더 간단하며 이름이 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 ]'
노트:
- 마지막 어설 션이 실패합니다. 위의 예와 달리 라이브러리는 아직 객체 할당을 지원하지 않지만 추가하기는 어렵지 않습니다. 곧 제공 될 컨테이너 / 반복기 지원과 함께 TO-DO에 배치 할 것입니다.
import 문은 기술적으로 필요하지 않지만 첫 번째 new 를 기다리지 않고 주어진 지점에서 클래스를 강제로로드 하여 올바른 순서로 항목을 초기화하는 데 도움이 될 수 있습니다. 한 번에 여러 인스턴스 변수를 쉽게 설정할 수 있습니다.
디버그 레벨, 생성자, 소멸자, 서브 클래 싱 및 기본 리플렉션 시스템도 있으며 에코를 대체하기 위해 print / println이 표시 됩니다 (대시로 시작하는 변수를 인쇄하려고합니까?). github의 예제는 클래스에서 HTML을 생성하는 CGI로 실행되는 것을 보여줍니다.
라이브러리 자체 (oop.lib.sh)는 그렇게 단순하지 않지만 (400+ 라인, 11K), 라이브러리를 포함하고 잊어 버리면됩니다.