Zsh에서 Bash 기능이 작동하지 않습니다.

Zsh에서 Bash 기능이 작동하지 않습니다.

저는 Bash에서 Zsh로 천천히 마이그레이션하고 있으며 한 가지 예외를 제외하고 제가 경험한 모든 것이 잘 작동하는 지점에 도달했습니다.

.bashrc내 프로그램에는 하루에 수십 번씩 사용하는 여러 기능이 있는데 그 중 두 개는 Zsh에서 작동하지 않습니다. 이 세 가지 기능은 기본적인 메모 기능을 구성합니다.

현재 위치는 다음과 같습니다 .config/zsh/functions.

function n() { 
local arg files=(); for arg; do files+=( ~/".notes/$arg" ); done
${EDITOR:-vi} "${files[@]}" 
}

function nls() {
tree -CR --noreport $HOME/.notes | awk '{ 
    if (NF==1) print $1; 
    else if (NF==2) print $2; 
    else if (NF==3) printf "  %s\n", $3 
    }'
}

# TAB completion for notes
function _notes() {
local files=($HOME/.notes/**/"$2"*)
    [[ -e ${files[0]} ]] && COMPREPLY=( "${files[@]##~/.notes/}" )
}
complete -o default -F _notes n

내 출처는 .zshrc다음과 같습니다.

autoload bashcompinit
bashcompinit
# source zshrc functions file
source "$HOME/.config/zsh/functions"

nls예상대로 작동하지만 작업을 완료하지도 완료 n하지도 않습니다 .Tab

나는 man zshcompsys그것을 읽었다:

bashcompinit 함수는 bash 프로그래밍 가능 완성 시스템과의 호환성을 제공합니다. 실행되면 동일한 이름의 bash 내장 함수에 해당하는 compgen 및 Complete 함수를 정의합니다. 그런 다음 bash용으로 작성된 완성 사양 및 기능을 사용할 수 있습니다.

그러나 완료하려고 하면 Tab아무 일도 일어나지 않고 n notenameVim은 /home내가 입력하는 동안 파일 브라우저 모드에서 내 파일을 엽니다. 이는 정확히 예상된 동작이 아닙니다.

다른 모든 정의된 함수는 정상적으로 작동합니다. Zsh에서 작동하도록 이러한 기능을 마이그레이션하는 방법은 무엇입니까?

답변1

  • local키워드가 아닌 내장 함수이므로 local files=(…)배열 할당으로 구문 분석하지 않고 문자열 할당으로 구문 분석합니다. 할당과 선언을 별도로 작성합니다. (이미llua님이 발견했습니다.files하지만 빈 배열로 초기화하거나 선언된 변수를 사용해야 합니다 typeset -a. 그렇지 않으면 배열이 허위 빈 요소로 시작됩니다. )
  • Zsh 배열은 bash 및 ksh에서처럼 0이 아닌 1부터 시작하여 번호가 지정되므로 ${files[0]}로 작성해야 합니다 . 또는 함수 시작 부분 $files[1]에서 zsh에게 ksh 및 bash와 더 호환되는 방식으로 작동하도록 지시하십시오 .emulate -L ksh
  • emulate이 경로를 따르지 않는 한 _notes기본적으로 일치하지 않는 glob이 오류를 트리거하기 때문에 함수가 완료되지 않으면 인쇄됩니다. 다음에 추가zsh: no matches found: foo*foo글로벌 예선 N일치하는 항목이 없으면 빈 배열을 가져오고 배열이 비어 있는지 테스트합니다.
  • 함수에는 하위 디렉토리의 주석에 영향을 미치는 또 다른 버그가 있습니다 . 예를 들어 존재하고 를 입력하면 대신 contain 로 설정 _notes되도록 완료될 때까지 접두사를 제거해야 합니다 .~/notes/foo/barn b<TAB>COMPREPLYbfoo/b

bash와 zsh 모두에서 파일을 읽을 수 있도록 유지하려면 다음을 수행하십시오.

type emulate >/dev/null 2>/dev/null || alias emulate=true
function n() {
  emulate -L ksh
  local arg; typeset -a files
  for arg; do files+=( ~/".notes/$arg" ); done
  ${EDITOR:-vi} "${files[@]}" 
}

function nls() {
  tree -CR --noreport $HOME/.notes | awk '{ 
      if (NF==1) print $1; 
      else if (NF==2) print $2; 
      else if (NF==3) printf "  %s\n", $3 
    }'
}

# TAB completion for notes
function _notes() {
  emulate -L ksh
  local x files
  files=($HOME/.notes/**/"$2"*)
  [[ -e ${files[0]} ]] || return 1
  COMPREPLY=()
  for x in "${files[@]}"; do
    COMPREPLY+=("$2${x#$HOME/.notes*/$2}")
  done
}
complete -o default -F _notes n

코드를 zsh로 포팅하려면 다음을 수행하세요.

function n() {
  local files
  files=(${@/#/~/.notes/})
  ${EDITOR:-vi} $files
}

function nls() {
  tree -CR --noreport $HOME/.notes | awk '{ 
      if (NF==1) print $1; 
      else if (NF==2) print $2; 
      else if (NF==3) printf "  %s\n", $3 
    }'
}

# TAB completion for notes
function _notes() {
  setopt local_options bare_glob_qual
  local files
  files=(~/.notes/**/$2*(N))
  ((#files)) && COMPREPLY=($2${^files##~/.notes*/$2})
}
complete -o default -F _notes n

답변2

zsh의 typeset(local) 명령은 해당 구문을 사용하여 배열을 정의할 수 없습니다. 배열을 생성할 수 있지만 하나의 명령으로 모든 값을 동시에 설정할 수는 없습니다.

function n() {                                                         
local arg files; for arg; do files+=( ~/.notes/$arg ); done
vim ${files[@]}
}

고치는 방법 중 하나입니다.

관련 정보