джерело сценарію Bash - Повернення помилки, а не виходу?


17

Я шукаю скрипт bash в терміналі , тому виходжу з помилки з

set -o errexit

вбиває мій термінал, який НАЙКРАЙНО ДУЖЕ, тому що я повинен закрити термінал, відкрити ще один і скинути деякі змінні.

Поки що, використовуючи

command || return

рядки, за сценарієм, роблять саме те, що я хочу

set -o errexit

робити ... Але я хочу, щоб це було зроблено для всього сценарію; не лише один рядок / команда

У мене є файл, повний команд для налаштування сайту, і я краще не виконую команду || повернення

для кожного окремого рядка у файлі

Чи є інший варіант встановлення чи щось інше, що просто "повернеться" замість виходу з терміналу?

- Просто для наочності я хотів би вбити сценарій і залишити термінал у тому ж стані, що натискання клавіші ctrl + C, щоб знищити службу, що працює в терміналі. command || returnробить це. Але я не хочу || returnдотримуватися кожного рядка у файлі. Тож я шукаю щось подібне set -o errexit, що не спричиняє вимкнення терміналу

--- Примітка. Створення німого сценарію з двома рядками в ньому (super.sh):

create_path=~/Desktop/site_builder/create.sh
source $create_path blah

І розміщуючи set -o errexitвгорі create.sh,

працює саме так, як я цього очікую. Однак насправді нерозумно створювати файл з двома рядками в ньому, просто викликати інший скрипт bash, а не просто викликати його з терміналу. Угххх

ось кілька прикладів:

в супер.ш

#!/bin/bash

create_path=~/Desktop/site_builder/create.sh
source $create_path blah

у create.sh

#!/bin/bash
set -o errexit
#line below this is a line that fails and will cause the script to stop and return to the terminal as expected 
sed "s/@@SITE_NAME@@/$dirname" 
~/Desktop/site_builder/template_files/base.html > ~/Desktop/$dirname/templates/base.html # a line with a stupid error

в терміналі:

 $ bash super.sh

вихід, як очікувалося:

my-mac$

Це працює. Яке дратівливе рішення.

Я хочу , в ідеалі, щоб виконати те , що в дурною файл super.sh від терміналу, а не файл super.sh: D, без терміналу вимикатися на мене. Ось що відбувається з тим, що я намагаюся зробити:

команда терміналу:

my-mac$ source $create_path blah

у create.sh у мене все ще є set -o errexit

Ось вихід на терміналі

    sed: 1: "s/@@SITE_NAME@@/blah": unterminated substitute in regular expression
Saving session...
...copying shared history...
...saving history...truncating history files...
...completed.

[Process completed]

І тоді термінал заморожений. Ctrl + C не працює, а також Ctrl + D

Якщо замість цього set -o errexit, якщо я просто використовую command || returnоператори скрізь у файлі create.sh, я отримую саме те, що хочу, виконуючи рядки в supser.sh безпосередньо на терміналі (замість виклику super.sh з терміналу). Але це теж не практичне рішення.

Примітка. Мені сподобалася відповідь @terdon про нерестування дочірньої оболонки, тож я закінчив просто нерест підрозділу через скрипт замість терміналу, як він показав у своїй відповіді за допомогою брекетів ( ), навколо всього сценарію. Його відповідь працює теж.


Ви робите це в сценарії чи вручну?
terdon

Я дзвоню файл з джерелом у терміналі. Як і в: source $file_path argumentСценарій виконується в тій же оболонці, з якої я його викликав (що sourceробить, мені сказали ... і діє так, як це відбувається) command || returnу файлі, який я

Гаразд, а де встановлений запуск? Це в джерелі джерела чи це ви виконуєте вручну? На це було б набагато простіше відповісти, якби ви могли додати простий приклад, який ми можемо скопіювати та спробувати. У мене є ідея, але мені потрібен спосіб тестування, щоб переконатися, що воно працює.
тердон

Я додав Примітку до початкової публікації, яка може допомогти в цьому. Але я також зроблю так, як ви запропонували.

Відповіді:


5

Просто створіть файл із відмовою від безпеки:

source the-source-file || true

... тоді загальна команда не вийде з ладу, навіть якщо є source.


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

Виявлення файлу не повертає вас до запиту оболонки ??
Jeff Schaller

ось що в моєму терміналі: Jills-MBP:~ jillr$ source ~/Desktop/site_builder/create.sh blah || trueвін просто виконує наступну частину сценарію з відмовою, тому повертається замість істинного. Єдине, що спрацювало - це command || returnзаяви у фактичному файлі для всіх команд, що нерозумно. Я не знаю, якщо кинути все це у функцію, то дзвінок function || returnу кінці файлу також принесе користь.

Ну, якщо ви явно поставите || returnкоманду, яка не вдається, так, вона повернеться. Я думав, що ми намагаємось утримати вашу головну / батьківську оболонку від виходу?
Jeff Schaller

Так, я хочу запобігти фактичному виходу терміналу. Тому що я не хочу виходити з терміналу. Я хочу вийти зі сценарію. Повернення окремих команд у сценарії виходить із сценарію і залишає мій термінал у тому ж стані, що і натискання Ctrl + C, щоб знищити процес, наприклад запуск сервера з терміналу. Я хочу уникати написання команди || повернення для кожного рядка у файлі: D

3

Це єдине, що працює для того, що мені потрібно було досягти (створити віртуальне середовище, потім активувати його, потім встановити вимоги з bash-скрипту):

породжують нижню оболонку / дочірню оболонку зі сценарію, як у:

дурний_файл.ш

(
set -o errexit
#bunch of commands
#one line fails
)

запустіть stupid_file за допомогою:

source stupid_file.sh <file arguments here> || true

КІНЕЦЬ.

** бере лук **

(кредит належить Джеффу та Тердону)


1
Це насправді не відрізняється від того, щоб просто виконати сценарій замість того, щоб його джерело.
чепнер

@chepner hmmm. Класно. Мені доведеться спробувати просто зателефонувати bash $create_path blahі побачити, чи все ще він працює і виконує такий самий спосіб, і все-таки правильно встановити речі у моє віртуальне середовище. Зараз немає часу.

Я заощаджую ваш час: він не вийде (якщо під "встановленням" ви маєте на увазі встановлення змінних оточуючих середовищ у вашій поточній оболонці), а також не буде (...), оскільки всі призначення в круглих дужках впливають лише на підзарядку. foo=3; (foo=5); echo "$foo"вийде 3, а не 5.
Чепнер

@chepner не зовсім. Я не можу зателефонувати source fileз терміналу і очікувати однакових результатів. Тому що це ніколи не спрацювало. Єдиний раз, коли я отримую ті ж результати, це коли я створюю явно підзарядну оболонку, чи то через термінал, чи через скрипт. Однак я можу використовувати bashзамість того, sourceщоб виконувати сценарій, і отримувати ті самі результати, але лише тоді, коли я виконую скрипт в під оболонці явно

@chepner, встановлюючи речі, я фактично маю на увазі створити віртуальне середовище, активувати це віртуальне середовище та виконати pip install -r $apath/requirements.txtвсередині цього активованого середовища. Ось чому я використав джерело, в першу чергу для виклику сценарію

1

Як просте вирішення, ви можете запустити оболонку в поточну оболонку та джерело. Щось на зразок:

  1. Відкрийте новий термінал і налаштуйте все так, як вам хочеться. Ви згадали про деякі змінні середовища тощо. Встановіть їх тут.

  2. У цьому терміналі запустіть нову оболонку. Так , наприклад, bash.

  3. Зробіть свою справу. Джерело сценарію. Якщо вона виходить, вас просто кидають у першу оболонку і все все налаштовано. Просто запустіть bashще раз, і ви знову в бізнесі.

Для ілюстрації я створив цей скрипт, який не вдасться, якщо спробувати його джерело:

$ cat /home/terdon/scripts/bar.sh
set -o errexit
var='bar

Давайте подивимося , що станеться , якщо я почну вкладений сеанс оболонки і його джерело (зверніть увагу , що я використовую портативний ім'я для sourceкоманди ., sourceє bashism):

parent-shell $ bash      ## start a new shell
child-shell $ . ~/scripts/bar.sh
bash: /home/terdon/scripts/bar.sh: line 2: unexpected EOF while looking for matching `''
parent-shell $ 

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


Я спробую це дуже швидко

Це має намічений ефект ... Недоліком є ​​те, що змінні, які я створюю для батьківської оболонки, недоступні в дочірній оболонці, яка містить одну із змінних, необхідних для виконання в дочірній оболонці. Чи є спосіб нерестувати нижню частину з файлу, який я виконую? Таким чином, я все ще можу викликати скрипт у батьківській оболонці і все ще можу отримати доступ до змінних, які мені потрібні? Я буквально налаштований create_path=~/Desktop/site_builder/create.sh у батьківську оболонку, тому що це роблю так часто. І мені це потрібно для виклику джерела $ create_path [аргумент] для виконання сценарію.

1
@JillRussek, якщо змінні не передаються дочірній оболонці, ви їх не використовуєте export. Але те, що ви описуєте, має дуже мало сенсу. Це все більше схоже на проблему XY . Ви можете поставити нове запитання, пояснюючи, яка ваша мета. Б'юсь об заклад, що ми можемо запропонувати вам краще рішення, що все це дивне джерело пошуку.
terdon

Хм. Я теж міг би зробити це. Зараз просто нерестування дочірньої оболонки зі скрипту замість терміналу робить саме те, що я хочу. Я маю джерело скрипту з терміналу, щоб створити віртуальне середовище в скрипті, і pip встановити в ньому речі. Це працює так, як задумано зараз.

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