Возврат логического значения из функции Bash

Я хочу написать функцию bash, которая проверяет, имеет ли файл определенные свойства и возвращает true или false. Тогда я могу использовать его в своих сценариях в "if". Но что мне вернуть?

function myfun(){ ... return 0; else return 1; fi;}

то я использую его следующим образом:

if myfun filename.txt; then ...

конечно, это не работает. Как это можно сделать?

Ответ 1

Используйте значение 0 для true и 1 для false.

Пример:

#!/bin/bash

isdirectory() {
  if [ -d "$1" ]
  then
    # 0 = true
    return 0 
  else
    # 1 = false
    return 1
  fi
}


if isdirectory $1; then echo "is directory"; else echo "nopes"; fi

Edit

Из комментария @amichair, это также возможно

isdirectory() {
  if [ -d "$1" ]
  then
    true
  else
    false
  fi
}


isdirectory() {
  [ -d "$1" ]
}

Ответ 2

Почему вы должны заботиться о том, что я говорю, несмотря на ответ 250+ upvote

Это не то, что 0 = true, а 1 = false. Это: ноль означает отсутствие отказа (успех) , а ненулевое значение означает отказ (типа N).

Хотя выбранный ответ технически является "верным" , пожалуйста, не вставляйте return 1 ** в свой код как ложный. У него будет несколько неприятных побочных эффектов.

  1. Опытные разработчики определят вас как любителя (по следующей причине).
  2. Опытные разработчики этого не делают (по всем причинам, указанным ниже).
  3. Это подвержено ошибкам.
    • Даже опытные разработчики могут ошибочно принять 0 и 1 как false и true соответственно (по вышеуказанной причине).
  4. Это требует (или будет поощрять) посторонние и смешные комментарии.
  5. На самом деле это менее полезно, чем неявные статусы возврата.

Изучить немного Баш

В руководстве по bash говорится (выделено мое)

return [n]

Заставить функцию оболочки прекратить выполнение и вернуть значение n вызывающей стороне. Если n не указан, возвращаемое значение - это статус завершения последней команды, выполненной в функции.

Следовательно, нам не нужно НИКОГДА использовать 0 и 1 для обозначения True и False. Тот факт, что они делают это, по сути, является тривиальным знанием, полезным только для отладки кода, вопросов для интервью и для того, чтобы поразить умы новичков.

В руководстве по bash также написано

в противном случае статус возврата функций - это статус завершения последней выполненной команды

В руководстве по bash также написано

($?) Расширяется до состояния выхода последнего выполненного переднего плана конвейера.

Ой, подожди. Трубопровод? Позвольте еще раз обратиться к руководству по bash.

Конвейер представляет собой последовательность из одной или нескольких команд, разделенных одним из управляющих операторов ‘| или ‘| & amp;.

Да. Они сказали, что 1 команда - это конвейер. Поэтому все 3 из этих цитат говорят одно и то же.

  • $? рассказывает, что произошло в последний раз.
  • Это пузырьки.

Мой ответ

Итак, хотя @Kambus продемонстрировал, что с такой простой функцией, return вообще не нужен. думаю  было нереально просто по сравнению с потребностями большинства людей, которые будут читать это.

Почему return?

Если функция собирается вернуть свой последний статус завершения команды, зачем вообще использовать return? Потому что это приводит к прекращению выполнения функции.

Остановить выполнение при нескольких условиях

01  function i_should(){
02      uname="$(uname -a)"
03
04      [[ "$uname" =~ Darwin ]] && return
05
06      if [[ "$uname" =~ Ubuntu ]]; then
07          release="$(lsb_release -a)"
08          [[ "$release" =~ LTS ]]
09          return
10      fi
11
12      false
13  }
14
15  function do_it(){
16      echo "Hello, old friend."
17  }
18
19  if i_should; then
20    do_it
21  fi

Что у нас здесь есть...

Строка 04 является явным [-ish] возвращаемым значением true, поскольку RHS из && выполняется только в том случае, если значение LHS было истинным

Строка 09 возвращает значение true или false, соответствующее статусу строки 08

Строка 13 возвращает false из-за строки 12

(Да, это можно проигнорировать, но весь пример придуман).

Еще один распространенный шаблон

# Instead of doing this...
some_command
if [[ $? -eq 1 ]]; then
    echo "some_command failed"
fi

# Do this...
some_command
status=$?
if ! $(exit $status); then
    echo "some_command failed"
fi

Обратите внимание, как установка переменной status демистифицирует значение $?. (Конечно, вы знаете, что означает $?, но кто-то менее знающий, чем вам, придется когда-нибудь его Google. Если ваш код не занимается высокочастотной торговлей, покажите немного любви, установите переменную.) Но реальный вывод состоит в том, что "если не существует статус" или, наоборот, "если выходной статус" можно прочитать вслух и объяснить их значение. Однако этот последний может быть слишком амбициозным, потому что, увидев слово exit, вы можете подумать, что он выходит из сценария, а в действительности он выходит из подоболочки $(...).


** Если вы абсолютно настаиваете на использовании return 1 для false, я рекомендую вам хотя бы использовать return 255 вместо этого. Это заставит вашего будущего себя или любого другого разработчика, который должен поддерживать ваш код, задать вопрос "почему это 255?" Тогда они, по крайней мере, будут обращать внимание и будут иметь больше шансов избежать ошибки.

Ответ 3

myfun(){
    [ -d "$1" ]
}
if myfun "path"; then
    echo yes
fi
# or
myfun "path" && echo yes

Ответ 4

Будьте внимательны при проверке каталога только с опцией -d!
если переменная $1 пуста, проверка все равно будет успешной. Разумеется, проверьте также, что переменная не пуста.

#! /bin/bash

is_directory(){

    if [[ -d $1 ]] && [[ -n $1 ]] ; then
        return 0
    else
        return 1
    fi

}


#Test
if is_directory $1 ; then
    echo "Directory exist"
else
    echo "Directory does not exist!" 
fi

Ответ 5

Это может сработать, если вы перепишете это function myfun(){ ... return 0; else return 1; fi;} как это function myfun(){ ... return; else false; fi;}. То есть, если false является последней инструкцией в функции, вы получаете ложный результат для целой функции, но return прерывает функцию с истинным результатом. Я верю, что это верно для моего переводчика bash, по крайней мере.

Ответ 6

Используйте команды true или false непосредственно перед вашим return, затем return без параметров. return автоматически использует значение вашей последней команды.

Предоставление аргументов для return является непоследовательным, специфичным для типа и подверженным ошибкам, если вы не используете 1 или 0. И, как говорилось в предыдущих комментариях, использование 1 или 0 здесь не является правильным способом приблизиться к этой функции.

#!/bin/bash

function test_for_cat {
    if [ $1 = "cat" ];
    then
        true
        return
    else
        false
        return
    fi
}

for i in cat hat;
do
    echo "${i}:"
    if test_for_cat "${i}";
    then
        echo "- True"
    else
        echo "- False"
    fi
done

Выход:

$ bash bash_return.sh

cat:
- True
hat:
- False

Ответ 7

Я столкнулся с моментом (явно не упоминавшимся?), На который я наткнулся. То есть не как вернуть логическое значение, а как правильно его оценить!

Я пытался сказать if [ myfunc ]; then ..., но это просто неправильно. Вы не должны использовать скобки! if myfunc; then ... это способ сделать это.

Как и в случае @Bruno и других, true и false являются командами, а не значениями! Это очень важно для понимания логических выражений в сценариях оболочки.

В этом посте я объяснил и продемонстрировал с помощью логических переменных: fooobar.com/questions/14195/.... Я настоятельно рекомендую проверить это, потому что это так тесно связано.

Здесь я приведу несколько примеров возврата и оценки логических значений из функций:

Это:

test(){ false; }                                               
if test; then echo "it is"; fi                                 

Не выводит эхо. (то есть false возвращает false)

test(){ true; }                                                
if test; then echo "it is"; fi                                 

Производит:

it is                                                        

(т.е. true возвращает true)

И

test(){ x=1; }                                                
if test; then echo "it is"; fi                                 

Производит:

it is                                                                           

Потому что 0 (то есть true) было возвращено неявно.

Это то, что меня напортачило...

test(){ true; }                                                
if [ test ]; then echo "it is"; fi                             

Производит:

it is                                                                           

и

test(){ false; }                                                
if [ test ]; then echo "it is"; fi                             

ТАКЖЕ производит:

it is                                                                           

Использование скобок привело к ложному положительному результату! (Я предполагаю, что "внешний" результат команды равен 0.)

Основной вывод из моего поста: не используйте скобки для оценки логической функции (или переменной), как вы это делаете для типичной проверки равенства, например if [ x -eq 1 ]; then...!

Ответ 8

Следуя @Bruno Bronosky и @mrteatime, я предлагаю вам просто написать свое булево возвращение "назад". Вот что я имею в виду:

foo()
{
    if [ "$1" == "bar" ]; then
        true; return
    else
        false; return
    fi;
}

Это устраняет уродливое требование в две строки для каждого оператора return.