Как работает этот скрипт svn?

Я определил эту функцию bash для обновления нескольких проектов svn с помощью одной команды:

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

Вывод, который он дает:

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

Summary of updates немного запутанно. Каждая строка печатается отдельным вызовом программы. Как может быть сводная сводка?

Короткий ответ: это не отдельные призывы; вы только запускаете svn update один раз.

(Вы можете проверить это, запустив функцию в set -x , которая делает bash печатать каждую команду при ее запуске: set -x; svn_update_all; set +x )

Если вы действительно хотите запустить svn несколько раз (и вы уверены, что у вас никогда не будет пробелов в ваших путях), вы можете просто отказаться от котировок вокруг $repos :

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

Вот дело с циклами. bash(1) говорит:

для имени [[ в [ слово ]]; ] сделать список ; сделанный

Список слов, следующих за ним, расширен, генерируя список элементов. Имя переменной по очереди устанавливается в каждый элемент этого списка, и список выполняется каждый раз.

Таким образом, содержимое блока for выполняется один раз для каждого слова после. Вот пример:

 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'

Но цитируемая строка берется как одно слово . Это в основном то, что происходит в вашем скрипте:

 count=0 for num in "one two three"; do let count++ echo "loop $count: '$num'" done 
 цикл 1: «один два три»

Удалите кавычки, и $repos снова разделится на отдельные слова, а затем svn update запускается один раз для каждого репо, как вы ожидали.

Заметьте, однако: это сломается, если у вас есть путь, в котором есть пробелы .

Самый простой способ обработки путей, которые могут иметь пробелы, заключается в том, чтобы вывести вывод find в read встроенную команду:

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

Самый безопасный способ – использовать действия find -execdir или -execdir , поэтому вам не нужно беспокоиться о разбиении файлов bash :

 # print the repo dir, then run "svn update" in it find . -name '.svn' -printf '%h: ' -execdir svn update \; 
 ./mpc: Обновление '.':
 U trunk / src / pow.c
 U trunk / tests / pow.dat
 U trunk / m4 / mpc.m4
 Обновлено до версии 1455.
 ./mpfr: Обновление '.':
 [и т.д]

либо удалить кавычки, либо

например

 for i in "ab" do echo $i done 

давать в качестве ауптута

 ab 

поэтому, скорее всего, вы закончите с

 svn update project1 project2 

следовательно, резюме.

пытаться

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