コマンドのアスタリスクによってforループが拡張されるのはなぜですか?

コマンドのアスタリスクによってforループが拡張されるのはなぜですか?

実行できるスクリプトを作成したいと思います。

git diff --name-status master..<BRANCH>

しかし、私がこれを実行した場合:

for i in $(git branch | grep -v master); do
   echo $i;
done

エコーアスタリスクのため、ディレクトリはエコーされますgit branch(現在のディレクトリにディレクトリがあります)。

* <SELECTED BRANCH>

*拡張される理由とそれを防ぐ方法は何ですか?

修正する:以下を使用してこれを防ぐことができます。

for i in $(git branch | tr -d '*' | grep -v master);
done;

しかし、なぜこれが起こるのですか?スターを削除するのはなぜですか?

ベストアンサー1

引用符のない変数やコマンドの置換(例:$iまたは$(git …)適用)分割+グローバル演算子文字列の結果に。それは:

  1. 変数値またはコマンド出力を含む文字列を設定します(後者の場合は最後の改行を除く)。
  2. 値に応じて文字列を別のフィールドに分割IFS
  3. 各フィールドをワイルドカードパターンとして解釈し、それを一致するファイル名のリストに置き換えます。パターンが一致するファイルがない場合は、そのままにしておきます。

git branch | grep -v master出力内容(ステップ1)は* master2つのフィールドに分割(ステップ2)され*(ステップ3)、現在のディレクトリのファイル名のリストmasterに置き換えられます。*

ワイルドカードを一時的に無効にするために実行できますset -f。別のアプローチはコマンドの置換を避け、代わりに入力の解析read。しかし、どちらも正しいことではありません。 git出力に必要なものよりも多くの内容が含まれているため、偽のブランチ名を取得します(*現在のブランチを表すフラグだけでなく、remotes/somewhere/foo -> barリモートトレースブランチなども含みます)。優雅ではなくても、次は安全だと思います。

for i in $(git branch | sed -e 's/^..//' -e 's/ .*//'); do
   echo $i
done

最も信頼できる方法は次のとおりです。git-for-each-ref

for i in $(git for-each-ref --format='%(refname:short)' refs/heads refs/remotes); do
  echo $i
done

おすすめ記事