Будь-який спосіб вийти з bash script, але не виходити з терміналу


183

Коли я використовую exitкоманду в сценарії оболонки, скрипт припиняє термінал (підказку). Чи є спосіб припинити скрипт, а потім залишитися в терміналі?

run.shОчікується, що мій сценарій буде виконаний безпосередньо з іншого джерела або з іншого сценарію.

EDIT: Щоб бути більш конкретним, є два сценарії run2.shяк

...
. run.sh
echo "place A"
...

і run.shяк

...
exit
...

коли я запускаю його . run2.sh, і якщо він потрапляє в exitкодову лінію run.sh, я хочу, щоб він зупинився до терміналу і залишився там. Але використовуючи exit, весь термінал закривається.

PS: Я намагався використовувати return, але echoкодова лінія все одно буде виконана ....


5
Мені дуже, справді, справді доводиться запитати: для чого ти використовуєш вихід у скрипті?
Ігнасіо Васкес-Абрамс

3
команда вихід не повинна припиняти ваш термінальний сеанс / логін. якщо ви використовуєте exit 0для завершення сценарію після успіху, під час запуску сценарію ex: ./test.shви повинні побачити вихід, але ваша консоль залишиться відкритою.
Бен Ештон

Ви можете використовувати shellкоманду, яка фактично відкриває термінал оболонки. Однак мій власний досвід полягає в тому, що цього не відбувається exit. Вихід зазвичай повертає контроль над батьківським сценарієм.
Віллем Ван Онсем

Відповіді:


258

"Проблема" насправді полягає в тому, що ви шукаєте джерело, а не виконуєте сценарій. Коли ви джерело файлу, його вміст буде виконуватися в поточній оболонці замість нерестування нижньої частини. Отже все, включаючи вихід, вплине на поточну оболонку.

Замість використання exitви хочете використовувати return.


2
Ось ще одне пояснення, яке мені здалося
3cheesewheel

Хоча це правильно, це не велика відповідь. Він ігнорує, що викликає скрипт може оголошувати змінні або функції, до яких потрібен доступ до цього виклику. Краще поясніть, як встановити зворотний код, а потім обробити його в runs.sh@ruakh, що краще відповісти на це питання.
MikeSchinkel

5
Що робити, якщо функцією є вкладений дзвінок? тобто дзвінки b, b дзвінки c, c хочуть негайно вийти з a і b.
Майкл

Джерело майже те саме, що копіювати пасту. Краще скористатись, sh <script>або bash <script>якщо хтось хоче запустити скрипт і закінчити в якийсь момент
peterchaula

42

Так; ви можете використовувати returnзамість exit. Його головне призначення - повернутися з функції оболонки, але якщо ви використовуєте її в sourceсценарії -d, він повертається з цього сценарію.

Як зазначено в пункті 4.1.1 "Бурлінські снаряди Борна" Посібника Баша :

     return [n]

Виклик функції оболонки для виходу зі зворотним значенням n . Якщо n не подано, значення повернення - це стан виходу останньої команди, виконаної у функції. Це також може бути використане для завершення виконання сценарію, який виконується вбудованим .(або source) вбудованим, повертаючи або n, або статус виходу останньої команди, виконаної в рамках сценарію, як статус виходу скрипту. Будь-яка команда, пов'язана з RETURNпасткою, виконується до того, як виконання буде відновлено після функції або сценарію. Стан повернення не дорівнює нулю, якщо returnвін використовується поза функцією, а не під час виконання сценарію шляхом .або source.


3
returnможна ТОЛЬКО використовуватись із функції. Якщо ви використовуєте returnта виконайте його як скрипт оболонки (наприклад sh run.sh), bash повідомить про помилку - return: can only повернеться 'з функції або скрипта джерела'
Tzunghsing David Wong,

@TzungsingDavidWong: Ви розумієте, що основна частина цієї відповіді є цитатою з офіційного посібника? І що повідомлення про помилку, яке ви цитуєте, узгоджується з цією відповіддю замість вашої претензії?
ruakh

Я з вами не згоден. Я просто хочу зазначити, що returnце не спрацює, якщо сценарій запускається як сценарій оболонки, а не виконується. (або source). До речі, де я можу знайти документ source -d?
Цунхсінг Девід Вонг

9

Замість запуску сценарію з використанням . run2.sh, ви можете запустити його, використовуючи sh run2.shабоbash run2.sh

Буде запущена нова підкольора, для запуску сценарію потім вона буде закрита в кінці сценарію, залишивши іншу оболонку відкритою.


Якщо так, то чому другий параметр sh "." run2.sh?
CHAN

@ H0WARD Ти маєш рацію, я забув видалити крапки. Зараз я відредагував відповідь.
Віорел Міреа

1
ОП чітко зазначає джерело як вимогу.
Джонатан Нойфельд

4

Ви можете додати додаткову команду виходу після оператора return / команда return, щоб вона працювала для обох, виконання сценарію з командного рядка та отримання джерела з терміналу.

Приклад виходу коду в сценарії:

   if [ $# -lt 2 ]; then
     echo "Needs at least two arguments"
     return 1 2>/dev/null
     exit 1
   fi

Рядок із exitкомандою не буде викликаний, коли ви надсилаєте скрипт після returnкоманди.

Під час виконання сценарію returnкоманда видає помилку. Отже, ми пригнічуємо повідомлення про помилку, пересилаючи його на /dev/null.


3

Насправді, я думаю, вас можуть збентежити, як ви кричите run a script.

Якщо ви використовуєте shдля запуску сценарію, скажімо, sh ./run2.shнавіть якщо вбудований скрипт закінчується exit, вікно термінала все одно залишиться.

Однак якщо ви користуєтесь .або source, ваше термінальне вікно буде закриватися та закриватися, коли закінчиться підпис.

для більш детальної інформації див. у чому різниця між використанням shта source?


2

Це так само, як ви помістите функцію запуску всередині свого сценарію run2.sh. Ви використовуєте вихідний код всередині run, тоді як джерело файлу run2.sh в bash tty. Якщо функція дати запустіть свою потужність, щоб вийти зі свого скрипту і надати run2.sh свою потужність для виходу з термінатора. Тоді, оскільки функція запуску має право вийти з вашого тематика.

    #! /bin/sh
    # use . run2.sh

    run()
    {
        echo "this is run"
        #return 0
        exit 0
    }

    echo "this is begin"
    run
    echo "this is end"

У всякому разі, я схвалюю з Kaz, що це проблема дизайну.


З тексту не зрозуміло, що ця відповідь намагається зробити, але це, безумовно, не вирішує питання.
Luís de Sousa

2

У мене була така ж проблема і з відповідей вище, і з того, що я зрозумів, що для мене в кінцевому підсумку було:

  1. Майте рядок shebang, який викликає призначений сценарій, наприклад,

    #!/bin/bashвикористовує bashдля виконання сценарію

У мене є сценарії з обома видами шебангу. Через це використання shабо .не було надійним, оскільки це призводить до неправильного виконання (наприклад, коли сценарій не працює, виконуючись неповно)

Відповідь, була така

    • Переконайтеся, що в сценарії є шебанг, щоб не було сумнівів щодо його призначеного обробника.
    • chmod .sh файл, щоб його можна було виконати. (chmod +x file.sh)
    • Закликайте його безпосередньо без будь-якого shабо.

      (./myscript.sh)

Сподіваюся, це допомагає комусь із подібними питаннями чи проблемами.


1

Я думаю, що це відбувається тому, що ви запускаєте його у вихідному режимі з крапкою

. myscript.sh

Ви повинні запустити це в підрозділі:

/full/path/to/script/myscript.sh

'джерело' http://ss64.com/bash/source.html


Вам не потрібен повний шлях до сценарію, якщо він . myscript.shпрацює. Щонайбільше, можливо, знадобиться ./myscript.sh.
Альваро Гонсалес

1

Це правильно, що використовуються джерела та виконані сценарії return порівняно, exitщоб підтримувати той самий сеанс, як інші.

Ось відповідна порада, якщо ви хочете будь-коли скрипт, який повинен тримати сеанс відкритим, незалежно від того, отримано чи ні.

Наступний приклад можна запустити безпосередньо на зразок foo.shабо як . foo.sh/ source foo.sh. Так чи інакше, він буде тримати сеанс відкритим після "виходу". $@Рядок передаються так , що функція має доступ до аргументів зовнішнього скрипта.

#!/bin/sh
foo(){
    read -p "Would you like to XYZ? (Y/N): " response;
    [ $response != 'y' ] && return 1;
    echo "XYZ complete (args $@).";
    return 0;
    echo "This line will never execute.";
}
foo "$@";

Результат терміналу:

$ foo.sh
$ Чи хотіли б ви XYZ? (Y / N): n
$. foo.sh
$ Чи хотіли б ви XYZ? (Y / N): n
$ |
(вікно терміналу залишається відкритим і приймає додатковий вхід)

Це може бути корисно для швидкого тестування змін скрипта в одному терміналі, зберігаючи купу коду брухту під основним exit / returnпід час роботи. Це також може зробити код більш портативним у певному сенсі (якщо у вас є безліч сценаріїв, які можна або не можуть викликати по-різному), хоча набагато менш незграбним для простого використання returnта, exitде це доречно.


0

якщо у вашому емуляторі термінала немає, -holdви можете очистити скрипт, що знаходиться в джерелі, і утримуйте термінал за допомогою:

#!/bin/sh
sed "s/exit/return/g" script >/tmp/script
. /tmp/script
read

інакше можна використовувати $TERM -hold -e script


0

Також переконайтеся, що повертаєтесь із очікуваним значенням повернення. В іншому випадку, якщо ви використовуєте exit, коли ви зіткнетеся з виходом, він вийде з базової оболонки, оскільки джерело не створює іншого процесу (екземпляра).


0

Для того, щоб написати сценарій , який є безпечним для запуску або як сценарій оболонки або джерел у вигляді файлу гс, сценарій може перевірити і порівняти $0і $BASH_SOURCEі визначити, exitможна безпечно використовувати.

Ось короткий фрагмент коду для цього

[ "X$(basename $0)" = "X$(basename $BASH_SOURCE)" ] && \
    echo "***** executing $name_src as a shell script *****" || \
    echo "..... sourcing $name_src ....."

-1

1) вихід 0 вийде зі сценарію, якщо він успішний.

2) вихід 1 вийде зі скрипту, якщо це збій.

Ви можете спробувати ці вище два на основі ur req.

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