2

I defined this bash function to update multiple svn projects with a single command:

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

The output it gives is:

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

The Summary of updates output is a little confusing. Each line is printed by a separate invocation of the program. How can there be a consolidated summary?

2 Answers 2

2

Short answer: those aren't separate invocations; you're only running svn update once.

(You can test that by running the function under set -x, which makes bash print every command as it is run: set -x; svn_update_all; set +x)

If you really want to run svn multiple times (and you're certain you will never have spaces in your paths), you can just drop the quotes around $repos:

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

Here's the deal with for loops. bash(1) says:

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.

So the contents of the for block runs once for each word after in. Here's an example:

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'

But a quoted string is taken as a single word. This is basically what's happening in your script:

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

Remove the quotes and $repos gets split into separate words again, and then svn update gets run once for each repo, as you expected.

Note well, though: this will break if you ever have a path that has spaces in it.

The simplest way to handle paths that might have spaces is to pipe the output of find into the read builtin command:

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

The safest way is to use find's -exec or -execdir actions, so you don't have to worry about bash splitting up filenames:

# 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]
0

either remove quotes, or pipe trough for

for instance

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

give as ouptut

a b

so most likely you end up with

svn update project1 project2

hence the summary.

try

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

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .