2015-11-24 2 views
2

В связи с this post on exiting a function in bashРекурсивная функция bash теряет способность возвращаться после спуска?

теряет ли рекурсивная функция Баш свою способность возвращаться после спуска?

Я попытался объяснить простой пример функции. Эта функция получает каталог и ищет файл .foo с базовым именем каталогов. Если этого не существует, его можно просто переименовать, но сначала нужно найти его. Я мог бы переписать это, конечно. Цикл поиска является причиной необходимости возврата. Мне просто интересно узнать о рекурсивном характере функций bash в этом случае.

given_directory=$"/home/bob" 
some_function "$given_directory" 

some_function() { 
    specific_foo_file=$"$1"/"$(basename "$1")".foo 
    if [ -f "$specific_foo_file" ] ; then 
     echo "do file stuff" 
    else 
     find . -name "*.foo"|while file ; do 
      if mv "$file" "$specific_foo_file" ; then 
       echo "renamed $file to $specific_foo_file" 
       some_function $given_directory 
       return 0 
      else 
       echo "could not rename $file" 
       return 1 
      fi 
     done 
     echo "can't find any .foo files, oh well" 
    fi 
} 

Пока эхо в конце всегда называется, если переименование было успешным.

EDIT: Для моего окружения я использую:

-bash-3.2$ uname -a 
SunOS XXXXXXXXXX 5.10 Generic_150400-29 sun4v sparc SUNW,SPARC-Enterprise-T5120 
+0

Если вместо «return 0» вы указали только «return», вы бы получили необходимый эффект (так как функция по умолчанию заканчивается статусом выхода последней команды). –

+1

Кроме того, запустите это через http://shellcheck.net/ и исправьте проблемы, которые он обнаруживает, поэтому нам не нужно описывать подробности. :) –

+0

Не имеет значения, какой код возврата 'find | в то время как 'return с' echo "не может найти ..." 'code будет * always * run. Ничто не мешает этому. –

ответ

3

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

some_function "$given_directory" || return 
  • Если some_function успешно, выполнение функции переходит к следующей строке.
  • Если some_function не работает, функция немедленно возвращается с тем же статусом выхода, что и для отказа.

Тем не менее, поскольку у вас есть return 0 как линия сразу же после вашего вызова функции, вы можете просто изменить это к голому return, и имеют тот же эффект.


Кроме того, у вас есть дополнительные серьезные проблемы в том, что ваш while цикл происходит в подоболочки, поэтому, когда он return с, это только последствия, которые подоболочка, а не внешнюю оболочку, которая вызывается его. Вместо этого, перестроить свой код, чтобы поставить логику внутри главного корпуса:

while IFS= read -r -d '' file ; do 
    if mv -- "$file" "$specific_foo_file" ; then 
     echo "renamed $file to $specific_foo_file" 
     some_function "$given_directory" || return 
    else 
     echo "could not rename $file" 
     return 1 
    fi 
done < <(find . -name '*.foo' -print0) 

См BashFAQ #24 понять эту проблему.

+0

@EtanReisner, вот почему я обсуждаю обе опции (изменения 'return 0' на просто' return' или добавление '|| return'). Конечно, если '0' удаляется из' return 0', '|| return' не добавляет значения. –

+0

Я предполагаю, что у OP все еще есть свое эхо после 'done', поэтому, если мы вообще не вернемся, мы получим статус 0 из этого. Кроме того, это означало бы, что мы продолжим обработку других файлов после сбоя (и, в конечном итоге, достигнем этого эха), а не короткого замыкания. –

+0

@CharlesDuffy Для моей версии find, '-print0' дает мне« find: bad option -print0 »любые предложения? – JaredTS486

Смежные вопросы