web-dev-qa-db-ja.com

ZshでBash関数が機能しない

私はゆっくりとBashからZshに移行し、1つの例外を除いて、移動したすべてのものがうまく機能するようになりました。

私の.bashrcには、1日に数十回使用する関数がいくつかあり、そのうちの2つはZshで動作しません。 3つの機能は、基本的なメモ取り機能を構成します。

現在.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 notenameに入ると、Vimはファイルブラウザモードで/homeを開きます-期待どおりの動作ではありません。

定義されている他のすべての関数はうまく機能します。これらの関数をZshで動作するように移行するにはどうすればよいですか?

7
jasonwryan
  • localは組み込みであり、キーワードではないため、local files=(…)は配列割り当てとしてではなく、文字列割り当てとして解析されます。宣言とは別に割り当てを記述します。 (すでに lluaで見つかりました ですが、filesを空の配列に初期化するか、変数をtypeset -aで宣言する必要があることに注意してください。そうしないと、配列は偽の空の要素で始まります。)
  • Zsh配列には、bashやkshのように0からではなく、1から番号が付けられているため、${files[0]}$files[1]と記述する必要があります。または、kshおよびbashとより互換性のある方法で動作するようにzshに指示します。関数の先頭にemulate -L kshを置きます。
  • emulateルートを使用しない限り、fooの補完がない場合、_notes関数はzsh: no matches found: foo*を出力します。 glob qualifierNを追加して、一致するものがない場合は空の配列を取得し、配列が空かどうかをテストします。
  • _notes関数には、サブディレクトリ内のメモに影響を与える別のエラーがあります。たとえば、次のように、プレフィックスを最後まで削除する必要があります。 ~/notes/foo/barが存在し、n b<TAB>と入力すると、COMPREPLYfoo/bではなく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

zshのtypeset(local)コマンドは、その構文で配列を定義できません。配列を作成することはできますが、1つのコマンドですべての値を設定することもできません。

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

それを修正する1つの方法です。

2
llua