zshエイリアス関数をパイプに渡す方法

zshエイリアス関数をパイプに渡す方法

zsh エイリアスがあります。

gitbs() {
    git branch | grep -- $1
}

次のように結果をgit checkoutに渡したいと思います。 git checkout | gitbs state どうすればこれを行うことができますか?

答え1

シェルパイプは、あるコマンドの出力を別のコマンドの入力に渡します。ここでは役に立ちません。コマンドの出力をコマンドライン引数として別のコマンドに渡そうとします。これを行うツールは次のとおりです。コマンドの置き換え。だから基本的なアイデアは

git checkout "$(gitbs state)"

(これはパイプですが、パイプの読み取り端はシェル自体です。出力を読み取ってから、その出力を含むコマンドラインを設定します。)

ただし、出力はgitbs state渡すのに正しい形式ではありませんgit checkout。ブランチ名と同じ行に追加のスペースがあり、時には句読点があります。 (色の書式設定コードもありますが、出力が端末に渡された場合、またはgitが自動的にポケットベルを呼び出す場合にのみ適用され、出力がパイプである場合はありません)。情報のエラーgit checkout

gitbsこの問題を解決するには、元のブランチ名を出力として生成するように変更できます。以下は、出力が端末の場合は人のためのきれいな形式を維持し、それ以外の場合は1行に分岐名を印刷するバージョンです。それを使うgit for-each-ref支店名を列挙します。これ条件式 -t 1標準出力が端末かどうかをテストします。

gitbs () {
  if [[ -t 1 ]]; then
    git branch
  else
    git for-each-ref --format='%(refname:lstrip=2)' 'refs/heads/*'
  fi | grep -- "$1"
}

この定義でgitbsそれはgit checkout "$(gitbs state)"すべてです。

コマンド置換の周りに二重引用符があります。二重引用符(git checkout $(gitbs state))がない場合、出力はスペースから別の引数に分割されるため、複数のブランチが一致すると、結果コマンドはチェックアウトするのではなく、ファイルの現在のバージョンをgit checkout foobar1 foobar2ifのバージョンで上書きします。名前のファイルが存在します。foobar1foobar2foobar1foobar2

gitbsこれらのトラップを回避するには、一致する単一のブランチが必要な別のバージョンを定義することをお勧めします。一致するブランチがゼロを超える場合、現在のブランチに関する追加メッセージは引き続き表示されますが、より明確なエラーメッセージが表示されますgit checkout。この関数は一致する分岐のリストを大量に

gitbs1 () {
  local branches
  branches=($(git for-each-ref --format='%(refname:lstrip=2)' 'refs/heads/*' | grep "$1"))
  if ((#branches == 0)); then
    echo "No branch contains '$1'" >&2
    return 3
  fi
  if ((#branches > 1)); then
    echo "Multiple branches match '$1':" >&2
    print -lr $branches >&2
    return 3
  fi
  echo $branches
}

これで自信を持って書くことができますgit checkout $(gitbs1 state)


このオプションをオンにするとglob_complete(つまりsetopt glob_complete.zshrc)次に入力できます。

子ブランチ *foo*Tab

*foo*一致するブランチの名前(存在する場合)に置き換えられます。一致するブランチが複数ある場合は、一般(プレフィックス)完了と同じ種類のメニューまたはループ動作が発生します。

答え2

これはエイリアスではなく関数です。

コマンド出力の単語を引数として他のコマンドに渡す場合は、コマンドの置き換えは次のようになります。

git checkout $(gitbs state)

キャプチャされた出力gitbs state(ここでは関数、エイリアス、または外部コマンドであるかどうかは重要ではありません)を取得し、末尾の改行、区切り文字を削除し、結果の単語を$IFS別の引数としてgit checkout1に渡します。

分割結果の最初の単語だけを渡します。

git checkout ${$(gitbs state)[1]}

出力全体(末尾の改行を除く)を次のように渡します。一つパラメータについては、git checkout以下を参照してください。

git checkout "$(gitbs state)"

$IFS文字の代わりに任意の文字列に分割するには、パラメータs拡張フラグを使用します(またはf改行に分割)。

git checkout ${(f)"$(gitbs state)"}

(空の要素は削除されます。)

このxargsコマンドはこの目的に使用できますが、分割はxargs非常に特定の方法で実行され、xargs外部コマンド(シェル組み込みまたは機能ではない)のみを実行できます。

gitbs state | xargs git checkout

xargs 多数の単語が出力される場合(単一のコマンドラインに入ることができるよりも多くの単語)、この操作は複数回実行できますgit checkoutgitbs state


set -o noglob1 Bourneなどの他のシェルでは、結果の単語に対するこの操作を防ぐためにワイルドカード()を無効にする必要があります。zshsh/ksh エミュレーションモード以外は適用されません。

関連情報