Повернення булева з функції Bash


211

Я хочу написати функцію bash, яка перевіряє, чи має файл певні властивості та повертає true чи false. Тоді я можу використовувати його у своїх сценаріях у "якщо". Але що мені повернути?

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

то я використовую це так:

if myfun filename.txt; then ...

звичайно це не працює. Як це можна досягти?


3
упустити functionключове слово, myfun() {...}достатньо
glenn jackman

2
Важливим ifє стан нульового виходу myfun: якщо він myfunвиходить 0, then ...виконується; якщо це щось інше else ... виконується.
Ельвакс

7
@nhed: functionключове слово - це башизм, і спричинить синтаксичні помилки в деяких інших оболонках. В основному це або непотрібно, або заборонено, так навіщо його використовувати? Він навіть не корисний як ціль grep, оскільки він може бути там (греп ()замість).
Гордон Девіссон

3
@GordonDavisson: що? є інші снаряди? ;-)
nhed

Будь ласка , не використовуйте 0 і 1. Див stackoverflow.com/a/43840545/117471
Бруно Bronosky

Відповіді:


333

Використовуйте 0 для істинного та 1 для хибного.

Зразок:

#!/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

Редагувати

З коментаря @ amichair такі можливі також

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


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

4
Ні, вам цього не потрібно - дивіться зразок.
Ерік

46
Для кращої читабельності ви можете скористатись командою 'true' (яка нічого не робить і успішно завершує, тобто повертає 0) та команда 'false' (яка нічого не робить і завершує невдало, тобто повертає ненульове значення). Також функція, яка закінчується без явного оператора return, повертає код виходу останньої виконаної команди, тому в наведеному вище прикладі тіло функції можна звести до лише [ -d "$1" ].
amichair

24
Бенгт: має сенс, коли ти вважаєш це "кодом помилки": код помилки 0 = все пішло нормально = 0 помилок; код помилки 1 = головне, що цей дзвінок повинен був зробити не вдалося; інше: провал! подивіться це на сторінці сторінки.
літаючі вівці

7
Це має сенс, якщо врахувати, що програмування речі зазвичай може досягти успіху лише одним способом, але може провалюватися нескінченними способами. Ну, може, не нескінченно, але партії шанси проти нас. Успіх / помилка (и) не є булевими. Я думаю, що це "Використовувати 0 для істинного та 1 для хибного". слід прочитати "Використовувати 0 для успіху та не нульове значення для відмови".
Давос

6
Будь ласка , не використовуйте 0 і 1. Див stackoverflow.com/a/43840545/117471
Бруно Bronosky

167

Чому тобі все одно, що я говорю, незважаючи на те, що є відповідь на 250+

Це не те, 0 = trueа 1 = false. Це: нуль означає відсутність відмови (успіх) і ненульовий означає збій (типу N) .

Хоча обрана відповідь технічно "правдива", будь ласка , не вводьте return 1** у свій код неправдивий . Це матиме кілька прикрих побічних ефектів.

  1. Досвідчені розробники помітять вас як любителя (з причини нижче).
  2. Досвідчені розробники цього не роблять (з усіх причин нижче).
  3. Він схильний до помилок.
    • Навіть досвідчені розробники можуть помилити 0 і 1 як помилкові та істинні відповідно (з вищезгаданої причини).
  4. Це вимагає (або заохочуватиме) сторонніх та смішних коментарів.
  5. Це насправді менш корисно, ніж неявні статуси повернення.

Вивчіть трохи баш

Посібник з bash говорить (наголос мій)

повернути [n]

Виконайте функцію оболонки, щоб зупинити виконання та повернути значення n його виклику. Якщо n не подано , значення повернення - це стан виходу останньої команди, виконаної у функції.

Таким чином, нам не доведеться ВСІХ разів використовувати 0 і 1 для позначення істинного та помилкового. Те, що вони роблять, це, по суті, тривіальне знання, корисне лише для налагодження коду, запитань інтерв'ю та душі у новачків.

У посібнику з bash також йдеться

інакше статус повернення функції - це стан виходу останньої команди, виконаної

У посібнику з bash також йдеться

( $? ) Розширюється до статусу виходу останнього виконаного переднього плану трубопроводу .

О, чекай. Трубопровід? Звернемося до посібника з bash ще раз.

Трубопровід - це послідовність однієї або декількох команд, розділених одним з операторів управління '|' або "| &".

Так. Вони сказали, що 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] істинним поверненням, тому що RHS &&виконується лише тоді, коли LHS був істинним

Рядок 09повертає істинну або помилкову, що відповідає статусу рядка08

Рядок 13повертає помилково через рядок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помилкових, пропоную вам принаймні використовувати це return 255. Це призведе до того, що ваша майбутня особа чи будь-який інший розробник, який повинен підтримувати ваш код, ставить питання "чому це 255?" Тоді вони принаймні будуть звертати увагу і матимуть більше шансів уникнути помилки.


1
@ZeroPhase 1 & 0 для хибних і правдивих було б смішним. Якщо у вас є двійковий тип даних, немає причин для цього. Що ви маєте справу з bash - це код статусу, який відображає успіх (однина) та невдачі (множина). Це " ifуспіх роби це, elseроби це". Успіх у чому? Може бути перевірка справжнього / хибного, може бути перевірка рядка, цілого числа, файлу, каталогу, дозволів на запис, глобул, регулярний вираз, grep або будь-яка інша команда, яка піддається помилкам .
Бруно Броноський

3
Уникати стандартного використання 0/1 як зворотного значення лише тому, що він тупий і схильний до плутанини, нерозумно. Вся мова оболонки тупа і схильна до плутанини. Сам Bash використовує 0/1 = істина / неправда конвенції в своїх власних trueі falseкоманд. Тобто ключове слово trueбуквально оцінює код статусу 0. Крім того, заяви від природи діють на булеві, а не на коди успіху. Якщо під час булевої операції трапляється помилка, вона не повинна повертати справжню або помилкову, а просто порушити виконання. Інакше ви отримуєте помилкові позитиви (каламбур).
Beejor

1
"if! $ (exit $ status); then" - Це заслуговує кращого пояснення. Це не інтуїтивно зрозуміло. Я повинен подумати про те, вийде програма перед тим, як надрукувати повідомлення, чи ні. Решта вашої відповіді була гарна, але це зіпсувало її.
Крейг Хікс

1
@BrunoBronosky Я прочитав вашу відповідь і, думаю, розумію різницю між контентним конвеєром (stdin-> stdout) та кодами помилок у зворотних значеннях. Але я не розумію, чому return 1слід уникати використання. Припускаючи, що у мене є validateфункція, я вважаю розумним, return 1якщо перевірка не вдасться. Зрештою, це причина зупинити виконання сценарію, якщо з ним не оброблено належним чином (наприклад, при використанні set -e).
JepZ

1
@Jepz, це чудове питання. Ви вірні, що return 1це дійсно. Я хвилююсь у всіх коментарях тут: "0 = вірно 1 = хибне [вставити негативне слово]" Ці люди, швидше за все, прочитають ваш код якогось дня. Тож для них бачення return 255(або 42 або навіть 2) повинно допомогти їм більше подумати над цим, а не помилитися як "справжнє". set -eвсе одно це спіймає.
Бруно Броноський

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

1
А як щодо заперечення?
einpoklum

Що з цим, @einpoklum?
Марк Рід

@MarkReed: Я мав на увазі до свого прикладу додати справу "else".
einpoklum

myfun "шлях" || ехо ні
Hrobky

13

Будьте уважні, перевіряючи каталог лише з опцією -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

1
Я не впевнений, як це відповідає на поставлене запитання. Хоча приємно знати, що порожній $ 1 може повернути істину, коли порожній, але він не дає ніякого розуміння того, як повернути істинне або хибне з функції bash. Я б запропонував створити нове запитання "Що відбувається, коли ви робите тест на порожній змінній оболонки?" А потім розмістити це як відповідь.
DRaehal

3
Зауважте, що якщо ви додасте правильне цитування до $1( "$1"), вам не потрібно перевіряти наявність порожньої змінної. Це [[ -d "$1" ]]не вдасться, оскільки це ""не каталог.
морги

3

Я зіткнувся з пунктом (ще експліцитно ще не згаданим?), Який я спотикався. Тобто, не як повернути булеве, а як правильно його оцінити!

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

Як на @Bruno та інші повторювали, trueі falseце команди , а не значення! Це дуже важливо для розуміння булів у скриптах оболонки.

У цій публікації я пояснив і демонстрував використання булевих змінних : https://stackoverflow.com/a/55174008/3220983 . Я настійно пропоную перевірити це, оскільки це так тісно пов'язане.

Тут я наведу кілька прикладів повернення та оцінки булевих функцій з функцій:

Це:

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

Не створює відлуння. (тобто false повертає помилкове)

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

Виробляє:

it is                                                        

(тобто true повертає правду)

І

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

Виробляє:

it is                                                                           

Тому що 0 (тобто істинне) поверталося неявно .

А ось ось що мене накрутило ...

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...!


2

Використовуйте команди 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

1

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


1

Я знайшов найкоротшу форму для тестування виведення функції просто

do_something() {
    [[ -e $1 ]] # e.g. test file exists
}

do_something "myfile.txt" || { echo "File doesn't exist!"; exit 1; }

1

З причини читабельності коду, я вважаю, що повернення true / false повинно:

  • бути на одній лінії
  • бути однією командою
  • легко запам’ятати
  • згадати ключове слово, returnза яким слідує інше ключове слово ( trueабо false)

Моє рішення є return $(true)або return $(false)як показано:

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

0

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

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

Це виключає потворну вимогу щодо двох рядків для кожного заяви про повернення.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.