поиск сценария Bash - Return on Error, а не Exit?

17

Я использую скрипт bash в терминале , поэтому при выходе

set -o errexit

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

Пока, используя

command || return

линии, в сценарии, делает именно то, что я хочу

set -o errexit

делать ... Но я хочу, чтобы это было сделано для всего сценария; не только одна строка / команда

У меня есть файл, полный команд для настройки сайта, и я бы предпочел не делать команду || возвращение

для каждой строки в файле

Есть ли другая опция set или что-то еще, что будет просто «возвращаться» вместо выхода из терминала?

- Просто для ясности , я хотел бы убить скрипт и оставить терминал в том же состоянии, в котором нажатие 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, вместо того, чтобы просто вызывать его из терминала. Ugghhh

вот несколько примеров:

в супер.ш

#!/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 о создании дочерней оболочки, поэтому я просто создал подпрограмму с помощью сценария, а не терминала, как он показал в своем ответе, используя фигурные скобки ( ), вокруг всего сценария. Его ответ тоже работает


источник
Вы делаете это в сценарии или вручную?
Тердон
Я вызываю файл с источником в терминале. Как в: source $file_path argumentСценарий выполняется в той же оболочке, из которой я его вызвал (что source, как мне сказали ... и действует так, как это) command || returnоператоры находятся в файле, который я выполняю в терминале
ОК, а где установлен запуск? Это в исходном скрипте или вы запускаете его вручную? На это было бы гораздо проще ответить, если бы вы могли добавить простой пример, который мы можем скопировать и опробовать. У меня есть идея, но мне нужен способ тестирования, чтобы убедиться, что он работает.
Тердон
Я добавил примечание к оригинальному сообщению, которое может помочь с этим. Но я тоже сделаю, как вы предложили.

Ответы:

5

Просто поставьте файл с отказоустойчивым:

source the-source-file || true

... тогда общая команда не потерпит неудачу, даже если это sourceпроизойдет.

Джефф Шаллер
источник
На самом деле, я подумал, что это то, что я хотел, но оказалось, что мой терминал просто работал медленно ... Я на самом деле хочу вернуться к терминалу при ошибке (то есть остановить весь скрипт в его треках) ... по какой-то причине, source file || true не делает этого и не делает, source file || return когда я
Сорсинг файла не возвращает вас к приглашению оболочки ??
Джефф Шаллер
это то, что находится в моем терминале: Jills-MBP:~ jillr$ source ~/Desktop/site_builder/create.sh blah || trueон просто выполняет следующую часть скрипта при неудаче, поэтому возвращает вместо true. Единственное, что сработало - это command || returnутверждения в реальном файле для всех команд, что глупо. Я не знаю, если все это добавить в функцию, то вызов function || returnв конце файла тоже пойдет на пользу.
Что ж, если вы явно включите || returnкоманду, которая потерпит неудачу, то да, она вернется. Я думал, что мы пытаемся не допустить выхода вашей основной / родительской оболочки?
Джефф Шаллер
Да, я хочу, чтобы терминал фактически не выходил. Потому что я не хочу выходить из терминала. Я хочу выйти из сценария. Возврат по отдельным командам в сценарии завершает работу сценария и оставляет мой терминал в том же состоянии, что и нажатие Ctrl + C, чтобы завершить процесс, такой как запуск сервера из терминала. Я хочу избежать написания команды || возврат для каждой строки в файле: D
3

Это единственное, что работает для того, что мне нужно было выполнить (создать виртуальную среду, затем активировать ее, затем установить требования из скрипта bash):

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

stupid_file.sh

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

запустите stupid_file, используя:

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

КОНЕЦ.

** берет лук **

(заслуга Джеффа и Тердона)


источник
1
На самом деле это ничем не отличается от простого выполнения сценария вместо его поиска.
chepner
@chepner хммм Здорово. Мне нужно будет просто позвонить bash $create_path blahи посмотреть, завершится ли он, работает ли он так же, и все равно правильно устанавливает вещи в мою виртуальную среду. Вне времени сейчас.
Я сэкономлю вам время: это не произойдет (если под «установкой вещи» вы подразумеваете установку переменных среды в вашей текущей оболочке), и не будет (...), так как все назначения в скобках влияют только на эту подоболочку. foo=3; (foo=5); echo "$foo"будет выводить 3, а не 5.
Чепнер
@chepner не совсем. Я не могу позвонить source fileс терминала и ожидать таких же результатов. Потому что это никогда не работало. Единственный раз, когда я получаю те же результаты, это когда я создаю вложенную оболочку явно, либо через терминал, либо из сценария. Однако я могу использовать bashвместо того, sourceчтобы выполнить сценарий, и получить те же результаты, но только когда я явно выполняю свой сценарий в вспомогательной оболочке
@chepner by install stuff, я на самом деле имею в виду создание виртуальной среды, активацию этой виртуальной среды, а затем выполнение 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 в родительской оболочке, потому что я делаю это так часто. И мне нужно вызвать source $ create_path [аргумент] для выполнения скрипта.
1
@JillRussek, если переменные не передаются в дочернюю оболочку, вы exportих не используете. Но то, что вы описываете, действительно имеет мало смысла. Это звучит все больше и больше как проблема XY . Возможно, вы захотите опубликовать новый вопрос, объясняющий, какова ваша конечная цель. Могу поспорить, что мы можем дать вам лучшее решение, чем все эти странные источники.
Тердон
Хм. Я мог бы дать этому шанс тоже. Прямо сейчас, просто порождение дочерней оболочки из скрипта, а не из терминала, делает именно то, что я хочу. Я должен получить скрипт из терминала, чтобы создать в скрипте виртуальную среду, и установить в нем вещи для установки в pip. Это работает, как задумано сейчас.
Но вы правы, я не экспортировал переменные, потому что я не знал, что мне нужно: D. (Я никогда раньше не создавал