# Bash와 Zsh에서 간단한 탭 자동완성 작성하기

> Clean Markdown view of GeekNews topic #22492. Use the original source for factual precision when an external source URL is present.

## Metadata

- GeekNews HTML: [https://news.hada.io/topic?id=22492](https://news.hada.io/topic?id=22492)
- GeekNews Markdown: [https://news.hada.io/topic/22492.md](https://news.hada.io/topic/22492.md)
- Type: news
- Author: [neo](https://news.hada.io/@neo)
- Published: 2025-08-13T11:01:02+09:00
- Updated: 2025-08-13T11:01:02+09:00
- Original source: [mill-build.org](https://mill-build.org/blog/14-bash-zsh-completion.html)
- Points: 12
- Comments: 1

## Summary

**Bash**와 **Zsh**에서 이미 완성된 단어에도 **설명**이 표시되는 **탭 자동완성** 기능을 구현하는 방법을 설명합니다. 두 셸의 **자동완성 API 차이**로 인해, Zsh의 설명 표시 기능을 Bash에도 지원할 수 있도록 **후보 문자열과 더미 후보**를 활용해 인터랙션을 동일하게 만들었고, 이를 통해 사용자는 **부분 완성, 전체 완성, 후보 설명 표시** 경험을 두 셸 모두에서 일관되게 사용할 수 있습니다.

## Topic Body

- **Bash**와 **Zsh**에서 이미 완성된 단어에도 설명을 표시하는 탭 자동완성 기능을 구현하는 방법 소개  
- Bash와 Zsh는 **서로 다른 탭 자동완성 API**를 사용하며, Zsh만 기본적으로 **자동 완성에 설명 보이기** 기능을 제공함  
- `_generate_foo_completions`로 후보를 생성하고, Bash에서는 `COMPREPLY`, Zsh에서는 `compadd`로 반환하는 구조를 구현함  
- Zsh의 설명 기능을 Bash에도 구현하기 위해 **후보 문자열에 설명을 포함**하고, 단일 후보일 때만 설명을 제거하는 방식으로 처리함  
- 단일 후보일 경우에도 **의도적으로 모호성을 추가**해 `&lt;TAB&gt;` 입력 시 설명이 표시되도록 개선함  
- 최종 스크립트는 두 쉘에서 동일한 사용자 경험을 제공하며, **부분 완성·전체 완성·후보 설명 표시** 모두 지원함  
  
---  
### 문제 배경  
- **탭 자동완성(tab-completion)** 은 명령어나 플래그를 탐색할 때 유용하며, 특히 API나 CLI 도구를 처음 접할 때 도움을 줌  
- Zsh는 기본적으로 **여러 후보가 있을 때만 설명을 표시**하고, Bash는 **별도 설정을 통해서만 가능**함  
- 하지만 **이미 완성된 단어**에 대해서는 두 셸 모두 **설명을 표시하지 않음**  
- 이로 인해 사용자가 설명을 보려면 다음과 같은 번거로운 과정을 거쳐야 함  
  - 일부 문자를 삭제하여 여러 후보가 매칭되도록 함  
  - `&lt;TAB&gt;` 키를 눌러 후보 목록을 확인  
  - 원하는 설명을 시각적으로 찾음  
  - 삭제한 문자를 다시 입력하여 명령 실행  
  
### 해결 방법 개요  
- 단일 후보일 경우에도 **더미 후보(dummy completion)** 를 추가하여 후보를 모호하게 만듦  
- 이렇게 하면 **Bash와 Zsh 모두 후보 목록과 함께 설명을 출력**하게 됨  
- 단, 실제 명령어에 설명 텍스트가 삽입되지 않도록 주의해야 함  
  
### 기본 개념  
- 탭 자동완성은 `&lt;TAB&gt;` 입력 시 현재 단어와 커서 위치를 받아, 가능한 후보 목록을 반환하는 방식으로 동작함  
- Bash: `COMPREPLY` 배열에 후보를 할당  
- Zsh: `compadd` 명령으로 후보를 등록  
- `_generate_foo_completions` 함수는 후보 문자열을 출력하며, 실전에서는 CLI의 상태를 기반으로 동적 생성 가능  
  
### Bash와 Zsh 동시 지원하기  
- `_complete_foo_bash`와 `_complete_foo_zsh` 함수로 각각의 쉘에 맞게 구현  
- `if [ -n "${ZSH_VERSION:-}" ]; then ... elif [ -n "${BASH_VERSION:-}" ]; then ... fi`로 구분  
- 사용자는 스크립트를 `.bashrc`나 `.zshrc`에 등록 후 적용  
  
### Zsh에서의 설명 표시  
- 후보 문자열에 `이름: 설명` 형식 사용  
- Zsh: `compadd -d raw -- $trimmed`로 이름과 설명을 병렬 배열로 전달  
- Bash: 설명 부분을 제거한 후보만 `COMPREPLY`에 전달 (기본적으로 설명 미지원)  
  
### Bash에서 설명 구현하기  
- 여러 후보일 경우 설명이 포함된 문자열을 그대로 노출  
- 단일 후보일 경우에만 설명 제거  
- Bash의 자동완성이 공통 접두어만 삽입하는 동작을 이용해 설명이 실제 입력에는 포함되지 않도록 함  
  
### 단일 후보에서도 설명 표시  
- 완성된 단어에 `&lt;TAB&gt;` 입력 시에도 설명을 보여주기 위해 **더미 후보**를 추가해 모호성을 유도  
- Zsh: 두 개의 병렬 배열(`raw`, `trimmed`) 모두에 더미 후보 추가  
- Bash: 단일 후보일 경우 `trimmed`에 이름만 추가  
  
### 최종 결과  
- 다중 후보 시 이름+설명 모두 표시  
- 단일 후보 시에도 `&lt;TAB&gt;`로 설명 확인 가능  
- Bash와 Zsh 모두 동일한 경험 제공  
- 적용 예:  
  ```  
  $ foo &lt;TAB&gt;  
  apple: a common fruit banana: starchy and high in potassium  
  apricot: sour fruit... cherry: small and sweet...  
  ```

## Comments



### Comment 42458

- Author: neo
- Created: 2025-08-13T11:02:02+09:00
- Points: 1

###### [Hacker News 의견](https://news.ycombinator.com/item?id=44854035)   
- fish에서 관심 있는 프로그램이 **man 페이지**를 제공한다면 `fish_update_completions`만 실행하면 됨  
  - 이 명령은 시스템의 모든 man 페이지를 파싱해 자동 완성 파일을 `~/.cache/fish/generated_completions/`에 생성함  
  - man 페이지가 부실하거나 없으면 직접 작성해 upstream에 기여할 수 있음  
  - fish의 포맷은 단순해서 공식 문서만 보면 충분함  
  - 예: `curl`의 `-L` → 'Follow redirects', `-O` → 'Write output to file named as remote file'  
  - 화면 공유할 때 사람들이 내가 zsh와 플러그인들을 쓰는 줄 아는데, 사실은 기본 설정만으로도 예쁜 fish를 쓰고 있음  
  - 하지만 `car TAB`이 `blkdiscard`로 확장되는 **비접두사 자동 완성** 때문에 cargo가 PATH에 없어도 오작동하는 점은 개선되면 좋겠음  
  - man 페이지 없이 `--help`만 제공하는 프로그램의 경우, fish에 zsh의 `_gnu_generic`이나 bash의 `complete -F _longopt` 같은 기능이 있는지 궁금함  
  - zsh에서도 man 페이지 기반 자동 완성을 생성하는 스크립트가 있음 → [zsh-manpage-completion-generator](https://github.com/umlx5h/zsh-manpage-completion-generator)  
  - OpenSUSE에서 `zypper search fish-completion`을 치면 200개가 넘는 패키지가 나와서 뭔가 수상하다고 느꼈음  
- bash 자동 완성이 점점 “똑똑해지면서” 현재 커서 위치에 파일명이 적절치 않다고 판단하면 파일/디렉토리 완성을 막는 점이 불편함  
  - 차라리 항상 **파일명 완성**으로 fallback하는 게 낫다고 생각함  
  - 이 때문에 완성 스크립트를 다 꺼버릴까 고민한 적도 있음  
  - bash에는 M-/에 바인딩된 `complete-filename`처럼 문맥 무시하고 파일명만 완성하는 함수들이 있음  
  - 특정 명령어의 파일 완성이 완전히 깨져서, `ls`로 먼저 완성한 뒤 명령어를 바꾸는 식으로 우회함  
  - 파일명이 존재하지만 실행 불가할 때는 “file foo.exe exists but it isn't executable” 같은 메시지를 주는 게 혼란이 덜함  
  - `complete -r` 실행 후 원하는 대로 동작하는 걸 보면 bash-completion 스크립트에 문제가 있는 듯함  
  - 웹 폼에서 이메일 입력 시, 첫 글자만 쳐도 “Invalid email!” 오류를 띄우는 **프론트엔드 검증**처럼 답답한 UX와 비슷함  
- 내가 작성한 글인데, 다른 사람들도 흥미롭게 읽었으면 함  
  - zsh 완성 스크립트를 매번 로드하는 대신 `$fpath`에 설치하면 캐시되어 **시작 속도**가 빨라짐  
  - Homebrew 배포 시 자동으로 completions를 설치할 수 있음  
  - zsh 완성은 규모가 커서 익히기 어렵지만, 회사에서 ansible 래퍼 스크립트에 플레이북별 옵션, 태그 자동 완성 등을 추가하며 점점 다듬고 있음  
- 최근 CLI 개발에 **usage** 라이브러리를 쓰기 시작했음 → clap과 통합되고, completions·argparse·man 페이지 생성 가능  
  - fish 스크립트의 argparse 블록을 교체할 가치는 고민 중이지만, optparse보다는 훨씬 나음  
  - 나도 비슷한 CLI 사양 정의 도구를 만들고 있는데, fish 지원을 막 추가했음  
- bash/zsh에서 JSON 필드 자동 완성을 지원하는 [fx.wtf](https://fx.wtf/install#autocomplete)를 소개함  
  - ijq보다 가볍지만, 상황에 따라 유용할 수 있음  
- zsh 내장 함수로 completer를 만드는 튜토리얼 → [zsh-completions-howto](https://github.com/vapniks/zsh-completions/blob/master/zsh-completions-howto.org)  
- 프로그램이 bash 스크립트를 작성하지 않아도 되게 하는 **표준 플래그**가 있는지 궁금함  
  - zsh에서는 `_gnu_generic`으로 `--help` 기반 간단 완성이 가능함  
  - Rust의 clap_complete, ripgrep의 `--generate` 옵션, PHP Symfony의 런타임 완성 생성 등 사례가 있음  
  - 공통 파서 라이브러리들이 자동으로 구현해주는 `--completion` 표준이 있으면 좋겠음  
- ksh에서는 배열 정의만으로 간단히 완성을 구현할 수 있음  
  - 예: `complete_kill_1` 배열에 시그널 이름을 넣으면 `kill` 명령 첫 인자 완성 제공  
  - 이게 ksh93 문법인지, oksh에 백포트된 건지 궁금함  
- 내가 만든 간단한 zsh 완성 스니펫 예시: `set-java-home` 함수에서 `~/apps/java/*` 목록을 버전으로 완성하도록 `_describe` 사용  
  - 거의 **원라인**에 가까운 간단한 구조임  
- LLM의 주된 기능이 자동 텍스트 완성이라 그런지, GitHub Copilot이 vscode 터미널에서 bash와 zsh 완성을 꽤 잘해줌
