Por que o asterisco no comando result in for loop está expandindo?

1

Eu quero escrever um script que será executado

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

mas quando eu executo isso:

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

Eu recebo um diretório echo porque git branch asterisco de eco (eu tenho um diretório no diretório atual)

* <SELECTED BRANCH>

Por que * é expandido e como posso evitar essa expansão?

UPDATE : posso evitar isso usando isso:

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

Mas por que isso está acontecendo? Por que preciso remover o asterisco?

    
por jcubic 19.08.2014 / 12:16

2 respostas

4

Variáveis não enumeradas e substituições de comandos como $i ou $(git …) aplicam-se a operador split + glob para o resultado da string. Isso é:

  1. Crie uma string contendo o valor da variável ou a saída do comando (menos as novas linhas finais no último caso).
  2. Divida a string em campos separados de acordo com o valor de IFS .
  3. Interprete cada campo como um padrão curinga e substitua-o pela lista de nomes de arquivos correspondentes; Se um padrão não corresponder a nenhum arquivo, deixe-o intacto.

A saída de git branch | grep -v master (etapa 1) contém * master , que é dividida (etapa 2) em dois campos * e master ; * é substituído (passo 3) pela lista de nomes de arquivos no diretório atual.

Você pode executar set -f para desativar temporariamente a globulação. Outra abordagem é evitar a substituição de comandos e, em vez disso, analisar a entrada com read . Nem a coisa certa, entretanto - você terá nomes de ramificação falsos, porque a saída do git contém mais do que você precisa (o sinal * para indicar a ramificação atual, mas também coisas como remotes/somewhere/foo -> bar para ramificações de rastreamento remoto) . Eu acho que o seguinte é seguro se deselegante:

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

Acho que a maneira mais robusta é usar git-for-each-ref .

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

Fluxos de texto como este devem ser lidos usando um while loop em vez de for , o que provavelmente está causando a questão (embora eu não possa reproduzi-lo). Uma maneira simples de fazer isso:

git branch | while IFS= read -r line
do
    echo "${line:2}"
done

Comparação:

$ cd -- "$(mktemp -d)"
$ git init
Initialized empty Git repository in /tmp/tmp.MJFmu7q7EH/.git/
$ touch README
$ git commit --allow-empty -m "Initial commit"
[master (root-commit) da46b03] Initial commit
$ git branch foo
$ git branch
  foo
* master
$ for i in $(git branch)
> do
>    echo $i
> done
foo
*
master
$ git branch | while IFS= read -r line
> do
>     echo "${line:2}"
> done
foo
master
    
por 19.08.2014 / 13:59