Como esse script svn funciona?

2

Eu defini essa função bash para atualizar vários projetos svn com um único comando:

svn_update_all () 
{ 
    repos='find . -name '.svn'';
    for i in "$repos";
    do
        svn update 'dirname $i';
        echo;
    done
}

A saída é:

Updating 'project1':
At revision 26713.
Updating 'project2':
At revision 26723.
Summary of updates:
  Updated 'project1' to r26713.
  Updated 'project2' to r26723.

A saída Summary of updates é um pouco confusa. Cada linha é impressa por uma invocação separada do programa. Como pode haver um resumo consolidado?

    
por Kshitiz Sharma 15.09.2015 / 10:19

2 respostas

2

Resposta curta: essas não são invocações separadas; você está executando apenas svn update uma vez.

(Você pode testar isso executando a função em set -x , que faz o bash imprimir todos os comandos durante a execução: set -x; svn_update_all; set +x )

Se você realmente quiser executar svn várias vezes (e tiver certeza de que nunca terá espaços em seus caminhos), basta soltar as aspas em torno de $repos :

svn_update_all ()
{ 
    repos='find . -name '.svn''
    for i in $repos
    do
        svn update 'dirname $i'
        echo
    done
}

Aqui está a transação com for loops. bash(1) diz:

for name [ [ in [ word ... ] ] ; ] do list ; done

The list of words following in is expanded, generating a list of items. The variable name is set to each element of this list in turn, and list is executed each time.

Portanto, o conteúdo do bloco for é executado uma vez para cada palavra após in . Aqui está um exemplo:

count=0
for num in one two three; do
do
    let count++
    echo "loop $count: '$num'"
done
loop 1: 'one'
loop 2: 'two'
loop 3: 'three'

Mas uma string entre aspas é considerada uma única palavra . Isso é basicamente o que está acontecendo no seu script:

count=0
for num in "one two three"; do
    let count++
    echo "loop $count: '$num'"
done
loop 1: 'one two three'

Remova as aspas e $repos será dividido em palavras separadas novamente e, em seguida, svn update será executado uma vez para cada repo, como esperado.

Note bem, no entanto: isso será quebrado se você tiver um caminho com espaços .

A maneira mais simples de manipular caminhos que podem ter espaços é canalizar a saída de find para o comando read builtin:

find . -name '.svn' | while read i
do
    svn update 'dirname $i'
    echo
done

A maneira mais segura é usar as ações find -exec ou -execdir , para que você não precise se preocupar com bash de divisão de nomes de arquivos:

# print the repo dir, then run "svn update" in it
find . -name '.svn' -printf '%h: ' -execdir svn update \;
./mpc: Updating '.':
U    trunk/src/pow.c
U    trunk/tests/pow.dat
U    trunk/m4/mpc.m4
Updated to revision 1455.
./mpfr: Updating '.':
[etc]
    
por 15.09.2015 / 17:08
0

remova as cotações ou a tubulação para

por exemplo

for i in "a b"
do
echo $i
done

dar como saída

a b

então é mais provável que você acabe com

svn update project1 project2

daí o resumo.

tente

find . -name '.svn' |
while read i
do
    svn update 'dirname $i';
    echo;
done
    
por 15.09.2015 / 11:29