Сообщение об ошибке bash, по-видимому, исходит из среды, а не из самого bash при выполнении внутри функции

Рассмотрим следующий простой bash-скрипт

cd nowhere

Это приводит к сообщению об ошибке, что-то вроде

my-script.sh: line 1: cd: nowhere: No such file or directory

Все идет нормально. Это имеет смысл. Давайте немного подправим это, обернув компакт-диск в функцию:

function go_nowhere { cd nowhere; }
go_nowhere

Мы получаем то же сообщение об ошибке. Это все еще имеет смысл. Давайте попробуем подоболочку вместо использования функции.

bash -c 'cd nowhere'

Опять же, аналогичное сообщение об ошибке, но теперь bash «подписывает» сообщение об ошибке своим собственным именем, а не именем нашего скрипта:

bash: line 1: cd: nowhere: No such file or directory

Пока что все еще имеет смысл. Теперь давайте сделаем и то, и другое! Мы обернем cd функцией и запустим эту функцию в подоболочке:

function go_nowhere { cd nowhere; }
export -f go_nowhere
bash -c 'go_nowhere'

Теперь сообщение немного другое. Во-первых, номер строки — «строка 0», а не строка 1. Это имеет смысл: поскольку мы использовали «экспорт», это означает, что с точки зрения подоболочки функция была определена «перед первой строкой», поскольку она была унаследована от его родитель. Но другое отличие более странное:

environment: line 0: cd: nowhere: No such file or directory

Что такое environment? Я не запускаю программу под названием «среда», так почему же bash печатает сообщение об ошибке, которое утверждает, что исходит из такой программы? Он пытается сказать мне, что ошибка находится в функции, унаследованной bash от среды? Мы можем проверить эту теорию:

function go_nowhere { cd nowhere; }
bash -c "`declare -f`; go_nowhere"

Номер строки снова стал больше, но сообщение об ошибке по-прежнему «подписано» как environment:

environment: line 3: cd: nowhere: No such file or directory

Теперь я действительно этого не понимаю. Он НЕ получил эту функцию из среды. Так откуда же берется строка environment? Обратите внимание, что это не относится только к сценариям... это можно воспроизвести в интерактивном режиме из приглашения: об ошибке внутри функции в подоболочке сообщается от environment, и я понятия не имею, почему

Он НЕ получил эту функцию из окружающей среды, но она получила! export -f сохраняет определения функций в переменных среды.

Shawn 19.07.2024 20:54

Расширение комментария Шона: export -f в родительской оболочке сохраняет функцию в среде этой оболочки (как переменную env со странным именем), и когда вы запускаете bash как подпроцесс (примечание: технически это не подоболочка, это немного отличается) она наследует эту среду и извлекает из нее определение функции. Итак, с точки зрения подпроцесса функция действительно пришла из окружающей среды.

Gordon Davisson 19.07.2024 21:15

@Шон: Я думаю, что точка зрения ОП заключается в том, что, хотя bash -c изначально получил функцию из среды, он впоследствии переобъявил ее (когда выполнил вывод declare -f), а это означает, что новая версия не из среды. (Очевидно, что-то в этом рассуждении не работает, но оно звучит правильно!)

ruakh 19.07.2024 21:16
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
3
3
61
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Что такое окружающая среда?

Это жестко запрограммированная строка в исходном коде bash здесь: https://github.com/bminor/bash/blob/master/make_cmd.c#L804.

  /* Assume that shell functions without a source file before the shell is
     initialized come from the environment.  Otherwise default to "main"
     (usually functions being defined interactively) */
  if (temp->source_file == 0)
    temp->source_file = shell_initialized ? "main" : "environment";

Не используйте обратные кавычки. Предпочитаю $(..). Проверьте свой код с помощью Shellcheck.

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

$ LC_ALL=C bash -s <<<"$(declare -f go_nowhere); go_nowhere"
main: line 3: cd: nowhere: No such file or directory

Как мы можем объяснить вывод этой команды: LC_ALL=C bash -s <<<"go_nowhere; $(declare -f go_nowhere); go_nowhere"

Philippe 20.07.2024 00:05

привет @Philippe Я не понимаю. Что тут объяснять? Что требует объяснения? Что вас смущает в выводе? Какой результат вы получаете? github.com/bminor/bash/blob/master/error.c#L96 тоже актуально.

KamilCuk 20.07.2024 09:17

На выходе одна строка содержит environment, другая main. Если shell_initialized один и тот же при запуске обоих, как мы можем объяснить разницу?

Philippe 20.07.2024 09:44

Вы экспортировали функцию export -f go_nowhere, поэтому первоначальный вызов поступает из среды, загружаемой при запуске bash до установки shell_initialized, до загрузки интерактивности. Напротив, если вы не экспортируете, в первой строке будет bash: line 1: go_nowhere: command not found. shell_initailized устанавливается довольно поздно github.com/bminor/bash/blob/master/shell.c#L822 . Я подозреваю, что функции загружаются где-то в shell_initialize()

KamilCuk 20.07.2024 09:54

Так что это всего лишь эвристика, и в данном случае она дала осечку. Имеет смысл. Спасибо!!

Mark VY 22.07.2024 14:51

И я действительно использую шеллчек, это спасение... Но я игнорирую это конкретное предупреждение... синтаксис обратной апострофа намного проще! Он менее визуально навязчив (на самом деле можно утверждать, что он почти невидим и, следовательно, СЛИШКОМ ненавязчив). И пальцам легче (0 сдвинутых символов против 3). Вложить это — полная катастрофа, но я все равно этого не делаю. (Оказывается, обратная косая черта тоже ведет себя странно... не осознавал этого.)

Mark VY 22.07.2024 14:51

Другие вопросы по теме

Как я могу выполнить произвольный код с помощью командной кнопки appShell (вместо отображения представления)?
В чем разница между использованием ; и && в сценариях package.json?
Как удалить все файлы, кроме файлов последнего дня в Linux?
Bash: чтение строки из файла с подстановкой переменных
Bash: как продолжить цикл, если условие X выполнено
Gawk зависает при использовании регулярного выражения для RS в сочетании с чтением непрерывного потока со стандартного ввода
Как написать выражение REGEXP_EXTRACT в конфигурации Google Cloud Logging json?
Powershell Невозможно найти диск. Диск с именем «C» не существует
Как передать интерактивную оболочку удаленной программы в стандартный вывод работающей программы на C++, которая запустила удаленную программу (с использованием BSUB -I)
Как создать скрипт для автоматизации приема данных GET с моего сайта Wordpress и POST на другой сервер