Rubish: Bash와 Ruby 사이의 격차를 메우다
수십 년 동안 Unix 셸은 시스템 관리와 자동화의 주요 인터페이스 역할을 해왔습니다. Bash가 업계 표준이지만, 복잡한 로직을 구현할 때 문법이 번거로워져 개발자들이 종종 쉘 스크립트와 Python이나 Ruby 같은 고수준 언어 사이를 오가게 됩니다. 여기서 Rubish가 등장합니다. 순수 Ruby로 작성된 Unix 셸로, 완전한 Bash 호환성과 깊은 Ruby 통합이라는 두 세계의 장점을 제공하고자 합니다.
Rubish는 단순히 Ruby로 구현된 셸이 아니라, 쉘 문법을 파싱해 Ruby 코드로 컴파일한 뒤 Ruby VM에서 실행하는 하이브리드 환경입니다. 이 아키텍처 덕분에 기존 Bash 스크립트를 수정 없이 실행하면서도 쉘 명령을 Ruby의 강력한 객체 지향 기능과 자연스럽게 섞어 사용할 수 있습니다.
하이브리드 경험: Bash 호환성과 Ruby 파워의 결합
Rubish는 핵심적으로 Bash 호환성에 엄격히 전념합니다. 프로젝트는 모든 Bash 기능을 지원하는 것을 목표로 하며, 호환되지 않는 스크립트를 버그로 간주합니다. 이를 통해 사용자는 새로운 셸을 실험하기 위해 기존 툴체인을 포기할 필요가 없습니다.
하지만 Rubish의 진정한 가치는 "Bash를 넘어서는 기능"에 있습니다. 이는 개발자들이 전통적인 쉘 제약을 탈피하도록 돕습니다:
Ruby 기반 로직 및 반복
복잡한 쉘 조건문을 다루는 대신, Rubish는 if, while, until 블록 안에 Ruby 표현식을 중괄호로 감싸서 사용할 수 있게 합니다. 쉘 변수는 자동으로 해당 표현식 내부의 로컬 변수와 바인딩됩니다:
COUNT=5
if { count.to_i > 3 }
echo 'count is greater than 3'
end
또한 Rubish는 Ruby 이터레이터 블록(.each, .map, .select)을 도입해 명령 출력의 각 라인을 Ruby 컬렉션처럼 우아하게 처리할 수 있게 합니다:
ls.select { it.end_with?('.rb') }.each { |f| puts f.upcase }
명령 체이닝의 새로운 방식
전통적인 파이프(|)는 그대로 사용할 수 있지만, Rubish는 점 표기법을 통한 메서드 체이닝을 도입합니다. 괄호로 명령을 열면 Ruby 메서드처럼 연속 작업을 연결할 수 있습니다:
# Equivalent to: cat file.txt | grep error
cat(file.txt).grep(/error/)
인라인 Ruby 평가
쉘을 REPL처럼 사용하는 경우, Rubish는 대문자로 시작하는 모든 라인을 직접 Ruby 코드로 평가합니다. 이를 통해 빠른 계산이나 Ruby 표준 라이브러리 조회 시 특수 이스케이프 문자를 사용할 필요가 사라집니다:
rubish$ Time.now
=> 2025-01-01 12:00:00 +0900
rubish$ Dir.glob('*.rb').sort
=> ["Gemfile", "Rakefile"]
고급 쉘 엔지니어링
Rubish는 현대 개발자 워크플로우를 위해 설계된 여러 정교한 기능을 포함합니다:
- Lazy Loading:
rbenv나nvm같은 도구로 인한 셸 시작 지연 문제를 해결하기 위해, Rubish는lazy_load블록을 제공합니다. 이는 초기화를 백그라운드 스레드로 미루어 프롬프트가 즉시 표시되고 환경 설정이 백그라운드에서 진행되도록 합니다. - Custom Programmatic Prompts: 정적 문자열 대신, 프롬프트를 Ruby 함수로 정의할 수 있어 매 프롬프트 갱신 시 동적으로 내용(예: 현재 Git 브랜치)을 렌더링할 수 있습니다.
- Restricted Mode: 보안을 위해
rubish -r옵션은 모든 Ruby 통합을 비활성화하고, 표준 쉘 문법만을 사용해 신뢰할 수 없는 스크립트를 실행할 수 있게 합니다. - Zsh Compatibility: Bash를 넘어 Rubish는 Zsh 스타일 기능도 포함합니다.
setopt,compinit, 그리고 경로 축약(a/c/a<Tab>→ 전체 경로) 등을 지원합니다.
개발자 관점 및 트레이드오프
이 프로젝트는 특히 깊은 통합에 따른 트레이드오프에 대해 기술 커뮤니티 내에서 흥미로운 논의를 촉발했습니다.
"Vibe‑Coding" 논쟁
몇몇 기여자는 프로젝트 개발에 LLM이 미친 영향을 언급했습니다. 한 댓글러 @ciconia는 일부 코드가 "뚫어볼 수 없는" 성격을 띠며, 코딩 에이전트를 사용함으로써 메서드가 지나치게 길어지거나 명확한 인터페이스 경계가 부족해 인간 개발자가 유사한 도구 없이 기여하기 어려워질 수 있다고 우려했습니다.
성능 및 이식성
고수준 언어로 구현된 셸은 언제나 성능 논쟁의 대상이 됩니다. 일부 사용자는 Ruby가 Python보다 빠르다고 주장하지만, Rubish가 Almquist 셸 같은 최소 셸에 비해 어떤 위치에 있는지에 대해서는 의문이 제기되었습니다. 또한 원격 환경에서의 실용적인 장벽도 존재합니다. @freedomben이 지적했듯이, 모든 원격 서버에 Ruby 런타임이 설치돼 있어야 한다는 점은 정적 바이너리 셸보다 이식성을 떨어뜨립니다.
"쉘 안의 객체"에 대한 매력
비판에도 불구하고 이 접근법에 대한 강한 수요가 있습니다. PowerShell 사용자들은 "객체를 다루는 Bash"에 대한 갈망을 표명했으며, method_missing을 활용해 쉘 명령을 동적으로 처리하는 것이 Ruby 메타프로그래밍의 완벽한 활용 사례라고 평가했습니다.
Rubish 임베딩
Rubish의 가장 강력한 측면 중 하나는 공개 API입니다. Ruby로 작성되었기 때문에 fork+exec이나 JSON 직렬화 없이도 다른 Ruby 프로그램에 임베드할 수 있습니다. 이를 통해 IDE 플러그인이나 터미널 에뮬레이터(예: 형제 프로젝트 Echoes)가 프로세스 내에서 Rubish 세션을 구동해 고급 구문 강조와 명령 실행에 대한 프로그래밍 제어를 제공할 수 있습니다.