ディレクトリ移動を便利にするコマンド zoxide の使い方

ディレクトリ移動を便利にするコマンド zoxide の使い方 (環境は Ubuntu でシェルは bash です )
zsh シェルだとディレクトリの移動に cd を省略してパスだけで移動できたりする。fish シェルでは cd と入力すると移動頻度に応じて補完されたり fisher install jethrokuan/z と zoxide とは別の z コマンドがあったりする。zsh/fish は補完が強力だったり他にも便利なとこがいっぱいあるんだろうけど bash でももっと便利にディレクトリ移動したい。
目次
概要
zoxide は移動したディレクトリのパスをデータベース(~/.local/share/zoxide)に保存して、移動頻度に応じてスコアを付ける。そのスコアが高いディレクトリは z コマンドで短いキーワードで移動できたり zi コマンドで上位表示される。
インストール
fzf コマンドが必要なのでインストールする
git clone --depth 1 https://github.com/junegunn/fzf.git ~/.fzf ~/.fzf/install
OR
sudo apt install fzf
zoxide のインストール (installation に載ってますが一応)
curl -sS https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | bash
OR
sudo apt install zoxide
~/.bashrc 追記。
eval "$(zoxide init bash)"
--cmd オプションを使えばコマンド名を z / zi から変更できるっぽい
使い方
cd コマンドと同様に z でディレクトリを移動するとデータベースに追加されてスコアが付けられる。
$ z ~/foo/bar/baz
z コマンドで移動すると次回から最後のディレクトリ名(検索対象が最後のディレクトリ名なので)で移動できるようになる
$ z baz $ pwd /home/user/foo/bar/baz
登録されてるディレクトリは短いキーワードで移動できる(データベースの登録件数が増えてくるとスコアによってどこに行けるか変わる)
$ z ~/Downloads $ z ~/ $ pwd /home/user $ z d $ pwd /home/user/Downloads
短いキーワードでどこに移動できるか確認
$ for v in $(echo {a..z}); do printf "%s: " "$v"; zoxide query "$v"; done
a: /home/user/Downloads
b: /home/user/Dropbox
c: /home/user/.local
d: /home/user/Downloads
e: /etc
f: /home/user/.config
.
.
.
zi コマンドは fzf を使ってベータベースに登録されてるディレクトリを検索して移動できる
$ zi
zoxideコマンド
z と zi はどちらも関数なので以下本体である zoxide コマンドの使い方。zoxide のヘルプはシンプルで分かりやすぎるのでヘルプ見る方がいいかもしれない。
type z で関数の内容が見れる
$ type z
z is a function
z ()
{
if [ "$#" -eq 0 ]; then
_z_cd ~;
else
if [ "$#" -eq 1 ] && [ "$1" = '-' ]; then
if [ -n "$OLDPWD" ]; then
_z_cd "$OLDPWD";
else
echo 'zoxide: $OLDPWD is not set';
return 1;
fi;
else
_zoxide_result="$(zoxide query -- "$@")" && _z_cd "$_zoxide_result";
fi;
fi
}
パスの追加とスコアのインクリメント(. で現在のディレクトリを追加)
$ zoxide add <path>
パスの削除(. で現在のディレクトリを削除)
存在しないディレクトリは自動で削除されるのでディレクトリを rm -rf しても zoxide remove の必要はない
$ zoxide remove <path>
パス一覧
$ zoxide query -l
スコア付きのパス一覧
$ zoxide query -ls
検索(最後のディレクトリ名で検索しているっぽい)
$ zoxide query conf /home/user/.config
fzf を使った検索
$ zoxide query -i
個人的な設定
z と zi は使わないので ~/.bashrc から eval "$(zoxide init bash)" を削除。
cd コマンドに z コマンドの機能を付けたいので alias で cd コマンドを関数に置き換える。zoxide 以外の部分は この記事にある cd コマンドを拡張するやつです。以下の関数を .bash_functions とかに書いて ~/.bashrc に読み込む。source ~/.bashrc でリロードすると反映される。--cmd で cd に置き換え可能だと書いてるけど試してない。
func_enhanced_cd() { local x2 the_new_dir adir index local -i cnt if [[ $1 == "--" ]]; then dirs -v return 0 fi the_new_dir=$1 [[ -z $1 ]] && the_new_dir=$HOME if [[ ${the_new_dir:0:1} == '-' ]]; then # # Extract dir N from dirs index=${the_new_dir:1} [[ -z $index ]] && index=1 adir=$(dirs +$index) [[ -z $adir ]] && return 1 the_new_dir=$adir fi # # '~' has to be substituted by ${HOME} [[ ${the_new_dir:0:1} == '~' ]] && the_new_dir="${HOME}${the_new_dir:1}" # # Now change to the new dir and add to the top of the stack pushd "${the_new_dir}" >/dev/null 2>&1 if [[ $? -ne 0 ]]; then local q v q="$(IFS=' '; echo "$*")" v="$(zoxide query $q 2>/dev/null)" # なんかダサいこと書いてるけどエラー表示させるために # zoxide query の検索がヒットしなければ # $the_new_dir を入れて再び pushd でエラーにする [ -z "$v" ] && v="${the_new_dir}" pushd "$v" >/dev/null [[ $? -ne 0 ]] && return 1 fi the_new_dir="$(pwd)" # ホームディレクトリとルートディレクトリは除外して # zoxide add でディレクトリの登録とスコアをインクリメントする local -a EXCLUDES=("$HOME" '/') local ok=true local v for v in "${EXCLUDES[@]}"; do [ "$the_new_dir" == "$v" ] && ok=false done "${ok}" && zoxide add "${the_new_dir}" >/dev/null 2>&1 # # Trim down everything beyond 11th entry popd -n +11 2>/dev/null 1>/dev/null # # Remove any other occurence of this dir, skipping the top of the stack for ((cnt = 1; cnt <= 10; cnt++)); do x2=$(dirs +${cnt} 2>/dev/null) [[ $? -ne 0 ]] && return 0 [[ ${x2:0:1} == '~' ]] && x2="${HOME}${x2:1}" if [[ "${x2}" == "${the_new_dir}" ]]; then popd -n +$cnt 2>/dev/null 1>/dev/null cnt=cnt-1 fi done return 0 } alias cd=func_enhanced_cd
使ってる関数に zi を組み込む。以下の関数を .bash_functions とかに書いて ~/.bashrc に読み込む。source ~/.bashrc でリロードすると反映される。
ff() { local -a MAXDEPTH=(-maxdepth 6) local -a HIDDEN=(-and ! -path '*\/\.*') local -a ARGS=() local FIND=false while (($# > 0)); do case "$1" in -*) [[ "$1" =~ ^-(.*[^afl0-9]+.*|)$ ]] && echo "Error: invalid option -- ‘$1‘" && return 1 [[ "$1" =~ ^-[^0-9]*([0-9]|[1-9][0-9]+) ]] && MAXDEPTH=(-maxdepth "${BASH_REMATCH[1]}") [[ "$1" =~ ^-[^-]*a ]] && HIDDEN=() [[ "$1" =~ ^-[^-]*f ]] && FIND=true [[ "$1" =~ ^-[^-]*l ]] && MAXDEPTH=() shift continue ;; esac ARGS+=("$1") shift done local v if "${FIND}"; then v=$(find "${ARGS[0]:-.}" "${MAXDEPTH[@]}" -type d "${HIDDEN[@]}" -and ! -regex '^\.$' -and ! -regex '.*/node_modules/.*' -print 2>/dev/null | sed -e "s/^${HOME//\//\\/}/\~/" | fzf --select-1 --no-multi) else # zoxide のパス一覧を fzf で検索する v=$(zoxide query -l | sed -e "s/^${HOME//\//\\/}/\~/" | fzf --query="$(IFS=' '; echo "${ARGS[*]}")" --select-1 --no-multi) fi [ -n "$v" ] && v="${v/~\//$HOME/}" [ -d "$v" ] && cd "$v" || return 0 }
この関数は ff すると zi コマンドのように fzf で検索して cd できる。ff -f すると find コマンドで現在のディレクトリ以下を探索した結果を fzf で絞り込んで cd できる。
一応 ff -f のその他のオプションを説明すると -fa で . から始まる非表示なディレクトリを検索対象に含める。 -f10 とか -数字 で階層制限を指定できる(デフォルトは local -a MAXDEPTH=(-maxdepth 6) の部分で 6)。-fl で階層制限なし。ホームディレクトリからすべてのディレクトリを検索する場合は ff -fal ~