elsa in mac

zsh, auto-suggestions 플러그인 strategy 확장 - 디렉토리 별로 명령을 기억하는 방법 본문

Terminal(CLI,TUI)

zsh, auto-suggestions 플러그인 strategy 확장 - 디렉토리 별로 명령을 기억하는 방법

elsa in mac 2026. 7. 25. 19:26

 

이번 포스트에서는 많은 사용자분들이 zsh에서 거의 필수적으로 사용하고 있는 auto-suggestions 플러그인에 대한 기능 확장과 관련된 내용입니다. 

zsh-autosuggestions 은 사용자가 zsh 에서 직접 입력한 명령행을 기역하고 있다가 첫 몇 글자를 키인 하면 가장 적합하다고 판별한 과거의 명령행을 제안하는 기능입니다. 덕분에 사용자는 매우 긴 명령을 일잃히 기억할 필요가 없이, 동일한 명령이나 유사한 명령을 쉽고 빠르게 다시 사용할 수 있습니다.


하지만, 한 가지 단점이 있는데 그것은 특정 디렉토리에 대한 변별력이 없다는 것입니다.
예를 들어, A라는 디렉터리와 B라는 디렉터리에서 각각 빌드를 하고, 생성된 바이너리를 ~/.local/bin/ 으로 복사를 한다고 가정을 해 봅니다. 과거에 cp(복사) 명령을 사용했다면 auto-suggestions에  의해 사용자가 cp를 키인 하는 순간 나머지 뒷부분을 제안하게 됩니다. 이것은 물론 현재 디렉터리에서 복사하고자 하는 대상과는 전혀 무관할 수 있습니다.  따라서, cp의 대상이나 목적지 경로를 수정해야 합니다. 하지만, 각 디렉터리에서 cp를 각 디렉터리 별로 기억한다면 어떨까요? 제안된 결과를 거의 그대로 사용할 수 있을 가능성이 커집니다. 이게 훨씬 편하겠죠?

이번 포스트에서는 auto-suggestions 의 strategy를 변경하여 임의의 디렉터리에서 내린 명령을 해당 디렉터리별로 기억하게 함으로 써 보다 더 효율을 높일 수 있도록 해 봅니다. 

zsh-autosuggestions 플러그인은 기본적으로 전역 history(`~/.zsh_history`)만 참조하여 명령어를 제안합니다. 사용자가 명령을 내리면 zsh는 $HISTFILE 환경변수에 따라 사용자가 내린 명령을 저장합니다. $HISTFILE의 기본값이 바로 ~/.zsh_history 입니다.  zsh-susgesstions의 알고리즘은 단순합니다. 사용자가 키인을 하면 .zsh_history 목록을 시간순(최신순)으로 스캔하여 가장 먼저 찾아지는 동일한 패턴의 명령을 찾아 제안하게 됩니다.

제안된 로직은 다음과 같습니다.

  1. 사용자가 명령을 내리면 해당 디렉토리의 inode 값을 확인하고 ~/.zsh_dir_history/ 디렉터리에 inode와 동일한 파일명이 있는 지를 확인.
  2. 만일 존재한다면, 사용자가 키인한 패턴과 일치하는 명령행을 찾고 그 결과를 제안.  만일 없다면 추가로 사용자 명령을 기록합니다. 제안 결과는 fallback 즉 기존의 auto-suggestions에서 동일하게 처리.
  3. 반대로 존재하지 않는다면, inode와 동일한 파일명을 만들고 그 파일에 사용자의 명령을 저장. 제안 결과는 fallback으로 처리.
  4. 저장 시 단순 명령은 제외. (clear, cls, ls, yazi, df ... 등등)
  5. auto-suggestions 에서는 디렉터리별 제안 검색을 우선적으로 처리.

자 그럼 구현을 해 봅니다. 
유닉스/리눅스 파일시스템에서 inode는 파일이나 디렉터리의 메타데이터를 저장하는 자료구조인데, 중요한 점은 mv/rename 시에도 inode 번호가 유지 됩니다. 즉, 해당 디렉터리 명이 변경되거나 다른 곳으로 이동하더라도 참조되는 target이 유지될 수 있다는 것입니다.

~/.zshrc 에 아래와 같이 코드를 추가합니다. 중요한 것은 source $ZSH/oh-my-zsh.sh 뒤에 붙여야 한다는 점입니다. 이것은 해당 함수가 auto-suggestions 플로그인이 로드된 후에 정의되어야 하기 때문입니다. 

# -- oh-my-zsh -----------------------------------------------
plugins=(
    # git
    # dnf
    fzf-tab
    zsh-autosuggestions
    zsh-syntax-highlighting
)

source $ZSH/oh-my-zsh.sh
# --------------------------------------------- oh-my-zsh ----

# ---- 디렉토리별 history (zsh-autosuggestions 커스텀 strategy) ----
# 현재 디렉토리에서 실행한 명령어를 우선 제안하고, 없으면 전역 history로 fallback
autoload -Uz add-zsh-hook

_preexec_dirhistory() {
  # 단일 단어 명령어(인자 없음)는 디렉토리 history에 기록하지 않음
  [[ "$1" != *" "* ]] && return   # 단일단어 명령 filtering
  local dir_hash=$(stat -c '%d:%i' . | md5sum | cut -c1-8)
  mkdir -p "${ZDOTDIR:-$HOME}/.zsh_dir_history"
  local histfile="${ZDOTDIR:-$HOME}/.zsh_dir_history/${dir_hash}"
  echo "$1" >> "$histfile"
}
add-zsh-hook preexec _preexec_dirhistory

_zsh_autosuggest_strategy_dirhistory() {
  local dir_hash=$(stat -c '%d:%i' . | md5sum | cut -c1-8)
  local histfile="${ZDOTDIR:-$HOME}/.zsh_dir_history/${dir_hash}"
  [[ -f "$histfile" ]] || return
  local result=$(tac "$histfile" 2>/dev/null | command grep -m1 "^${1//\*/\\*}")
  [[ -n "$result" ]] && typeset -g suggestion="$result"
}

ZSH_AUTOSUGGEST_STRATEGY=(dirhistory history)

auto-suggestions 플러그인의 소스코드는 전혀 수정할 필요가 없습니다. auto-suggestions 가 동적 strategy를 호출할 수 있도록 구조화되어 있기 때문입니다. 

위와 같이 수정을 했다면, 현재 터미널에서는 suorce ~/.zshrc 를 해 주면 되고, 다른 터미널을 열면 자동으로 적용됩니다. 

동작순서는 다음과 같습니다. 

사용자가 명령을 입력하면 zsh의 preexec hook 이 _preexec_dirhistory()를 호출합니다. 이 함수는 현재 디렉터리(pwd)의 inode 값을 hash로 변환하여 ~/.zsh_dir_history/ 디렉터리에 파일을 만들고 해당 명령어를 저장합니다. 저장 시 인자가 없는 단일 단어 명령어는 history에서 제외됩니다. 이는 `[[ "$1" != *" "* ]] && return 조건에 의해 공백(인자) 유무를 판단하여 처리되기 때문입니다. 이후  zsh_autosuggestions 플러그인이 키 입력 시, history stragegy를 사용하는데,. zshrc에서 mapping 한zsh_autosuggest_strategy_dirhistory() 함수가 호출되어 같은 디렉토리에서 과거에 입력한 명령행 중 일치하는 패턴을 찾아 제안합니다. 

위의 스샷을 보면, 각각 다른 디렉토리에서 동일한 cp를 키인 했을 때, 제안되는 결과가 다르다는 것을 확인할 수 있습니다. 

공유하기 링크
Comments