zshコマンドでパスの終わりのルートを参照する方法は?

zshコマンドでパスの終わりのルートを参照する方法は?

私はしばしばgitリポジトリを複製し、そのルートディレクトリに移動します。たとえば、

$ git clone https://github.com/hpjansson/chafa && cd chafa

ccこれをより簡単にするために、次のように拡張されるzsh略語があります&& cd !#:2:t

typeset -Ag abbrev
abbrev=(
  'G' '| grep -v grep | grep'
  'L' '2>&1 | less'
  'V' '2>&1 | vipe >/dev/null'
  'ac' '| column -t'
  'bl' '; tput bel'
  'cc' '&& cd !#:2:t'
  'fl' "| awk '{ print $"
  'ne' '2>/dev/null'
  'pf' "printf -- '"
  'sl' '>/dev/null 2>&1'
  'tl' '| tail -20'
)
__abbrev_expand() {
  emulate -L zsh
  setopt EXTENDED_GLOB
  local MATCH
  LBUFFER=${LBUFFER%%(#m)[a-zA-Z]#}
  if [[ "${LBUFFER: -1}" == ' ' ]]; then
    LBUFFER+=${abbrev[$MATCH]:-$MATCH}
    if [[ $MATCH = 'fl' ]]; then
      RBUFFER="}'"
    elif [[ $MATCH = 'pf' ]]; then
      RBUFFER="\n'"
    fi
  else
    LBUFFER+=$MATCH
  fi
  zle self-insert
}
zle -N __abbrev_expand
bindkey ' ' __abbrev_expand
bindkey -M isearch ' ' self-insert

!#man zshexpn(セクションHISTORY EXPANSION、サブセクションEvent Designators)で説明されているように、現在のコマンドラインを参照します。

!# これまでに入力された現在のコマンドラインを確認してください。行は、引用符付きの行の前の単語を含む完全なものと見なされます!#

:2コマンドラインの2番目の単語を参照します(コマンドを入力したときのURLです$ git clone)。

n n番目のパラメータです。

そして:t単語の終わりを示します。

t すべての先行パス名コンポーネントを削除し、後続コンポーネントはそのまま残します。まるでbasename


通常、git cloneコマンドラインに入力してプロジェクトのURLをコピーして貼り付け、スペースを挿入してから別ccのスペースを挿入すると、必要なコマンドが表示されます。

ただし、コピーして貼り付けたURLが拡張子で終わる場合があります.git。これが発生すると、拡張子に!#:2:t不要な拡張子が含まれます.git

$ git clone https://github.com/hpjansson/chafa.git cc
$ git clone https://github.com/hpjansson/chafa.git && cd !#:2:t
$ git clone https://github.com/hpjansson/chafa.git && cd chafa.git
cd: no such file or directory: chafa.git

:r1つの解決策は、修飾子を使用して.git拡張を削除することです。

r ファイル拡張子を削除し、ルート名を保持します。ファイル拡張子のない文字列は変更されません。ファイル拡張子の後には、いずれも .任意の数の文字(0を含む)が続き、文字列の最後まで続きます。たとえば、拡張子はisであり、拡張子はありません。./foo.orig.c.cdir.c/foo

                                                               vv
$ git clone https://github.com/hpjansson/chafa.git && cd !#:2:t:r
$ git clone https://github.com/hpjansson/chafa.git && cd chafa

.gitただし、パスが拡張で終わらない場合、拡張は失敗し、gitコマンドまたはcdコマンドはすべて実行されません。

以下は、問題を説明する最小限の例です。

$ echo /foo/bar.baz !#:1:t:r
/foo/bar.baz bar

$ echo /foo/bar !#:1:t:r
zsh: modifier failed: r

最初のコマンドは最後のパスコンポーネントに拡張子が含まれているため成功します.bazが、2番目のコマンドは拡張子がないため失敗します。 OTOHはbashの4.3.48両方のコマンドが期待どおりに機能します。

:r文書には次の文が含まれているため、拡張なしではなぜ失敗するのか理解できません。

ファイル拡張子のない文字列は変更されません。

:r拡張子なしで文字列を使用するのが間違っているという意味ではありません。


拡張子を削除するために修飾子を使用する別のアプローチを試しました:s。私の考えには、次HIST_SUBST_PATTERNのオプション設定が必要だと思います。

setopt HIST_SUBST_PATTERN

このオプションを使用すると、拡張子を削除するために書き込むことができます:s/.*

                          vvvvv
$ echo /foo/bar.baz !#:1:t:s/.*
/foo/bar.baz bar

拡張がある場合は機能しますが、拡張がないと再び失敗します。

$ setopt HIST_SUBST_PATTERN
$ echo /foo/bar !#:1:t:s/.*
zsh: substitution failed

bar/foo/bar.bazinとto inの両方を参照できるbar単一の修飾子シーケンスはありますか/foo/bar

私はそれを使用していますzsh 5.7.1-dev-0 (x86_64-pc-linux-gnu)

ベストアンサー1

履歴拡張によってこれを行う方法は思い出されません。しかし、私は履歴拡張が最高のツールだとは思わない。これは非常に制限的です。からリングウィジェットを使用すると、コマンドラインにアクセスして任意のコードを操作できます。これを活用してください。

一つの方法は略語を拡張することです。$abbrev[$MATCH]代替を使用してください${(e)abbrev[$MATCH]}。明らかに特殊文字を正しく参照するには、略語を変更する必要があります。の場合は、cc次のようなものを使用してください。

&& cd ${${(z)BUFFER}[3]}

の特定の場合、git cloneおよびより一般的には、現在のディレクトリ内にディレクトリを作成するすべての場合には、別の略語を使用できます。新しく作成したディレクトリに切り替えます。git clone https://example.com/foo.git、for、およびgit clone https://example.com/fooforgit clone https://example.com/foo.git barだけでなく、for tar xf foo.tar(アーカイブに最上位のディレクトリがある場合)およびでも機能しますmv /some/directory .

&& cd *(/oc[1])

おすすめ記事