Избегайте многократного импорта скриптов.

Вопрос или проблема

В данный момент, когда я открываю терминал на своем Mac, он автоматически вызывает:

source ~/.bash_profile.

Меня, однако, озадачивает тот факт, что моя оболочка, похоже, не унаследовала никакого содержимого из ~/.bashrc или ~/.profile. Но это может быть типично.

У меня есть несколько скриптов, которые нужно загружать с помощью source или .; если я помещаю эти вызовы в ~/.bash_profile, загрузка нового окна оболочки может занять некоторое время, иногда 3 или 4 секунды, и это становится утомительным. Я предполагаю, что существует способ загрузить эти скрипты лишь один раз и сделать так, чтобы мой файл ~/.bash_profile каким-то образом наследовал это.

Обратите внимание, что вызов source ~/.bashrc или source ~/.profile из моего ~/.bash_profile – это не то, что я хочу сделать, и, вероятно, это плохая идея. Это не то, что я хочу сделать, потому что это не решает проблему медленной загрузки для каждой новой оболочки.

Я добавил несколько операторов вывода; каждый раз, когда я открываю новое окно терминала bash, это фиксируется:

начинаю загрузку /etc/profile
завершил загрузку /etc/profile
начинаю загрузку bash_profile
завершил загрузку bash_profile

это имеет смысл, но что расстраивает – мне действительно нужно загружать их каждый раз, когда открывается новая оболочка? Почему не может быть какой-то хитрой наследственности, чтобы нам не приходилось перезагружать все каждый раз?

Я создал видео, демонстрирующее проблему. У меня есть 4 приложения терминала, которые я регулярно использую:

terminal.app                  # ведет себя неправильно
iterm2                        # ведет себя неправильно
webstorm терминальный эмулятор    # ведет себя неправильно
vscode терминальный эмулятор      # ведет себя правильно!

VSCode на самом деле ведет себя так, как я бы хотел. Я предполагаю, что он делает это, загружая ~/.bash_profile в родительской оболочке и делая это только один раз, когда vscode запускается. Все окна терминала в приложении затем являются подпроектами этой одной родительской оболочки.

Надеюсь, это видео прояснит проблему:
https://www.useloom.com/share/4e62f0cb24434c4a83b8bd32844b596a

Это настоящая проблема – большинство приложений для терминала делают это неправильно, однако, довольно чудесным образом, похоже, что VSCode от Microsoft на самом деле делает это правильно, см. эту проблему:

https://youtrack.jetbrains.com/issue/WEB-31390

Мне интересно, было бы лучше писать клише на стороне загружаемого, а не на стороне загрузки. (например, заголовочные файлы C)

[[ "${_NAME_OF_THIS_LIBSCRIPT:-""}" == "yes" ]] && return 0
_NAME_OF_THIS_LIBSCRIPT=yes

С этим вам не нужно повторять один и тот же стандартный текст каждый раз, когда вы загружаете файл скрипта, который должен содержать что-то, предназначенное для совместного использования в нескольких местах.
Или я что-то упускаю?
Если быть честным, я не мастер программирования на bash, поэтому я действительно хотел бы получить идеи от других.

Сегодня утром я перенес кучу личной информации из своего bash_profile и bashrc и добавил их в новый файл, который я называю privaterc.

В своем файле privaterc я установил эту переменную:

PRIVATERC_RUN=yes 

Теперь в своем bash_profile я добавил эту строку:

[[ $PRIVATERC_RUN != yes && -f ~/.privaterc ]] && source ~/.privaterc

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


Что касается странностей профиля, которые вы наблюдаете, статья, на которую я ссылался в комментарии, утверждает следующее о mac:

Mac OS X — исключение

Исключением из руководящих принципов окон терминала является Terminal.app в Mac OS X, который по умолчанию запускает входную оболочку для каждого нового окна терминала, вызывая .bash_profile вместо .bashrc. Другие GUI-эмуляторы терминала могут делать то же самое, но большинство из них этого не делают.

Поместите уникальную переменную в rc файл – с длиной 1 или более символов – затем проверьте, имеет ли она длину больше 0 перед загрузкой bash_profile.

if [ ! X”” = X”$uniq_var” ] ; then . ~/.bash_profile ; fi

Я просто установил bash в качестве входной оболочки на MacOS и не столкнулся с этой проблемой. Возможно, они снова что-то изменили.

Это моя версия теста, основанная на ответе Hiroshi_U.

Я хочу протестировать функцию в mylib.sh с помощью $ source mylib.sh;sysLog Hey, функция не будет актуальна, если я изменил что-то после этого и пытаюсь получить более новый результат. Мне нужно удалить _NAME_OF_THIS_LIBSCRIPT, чтобы сделать ее новой. Поскольку $ echo $0 выдает что-то вроде -sh и -bash, я проверяю на -, чтобы определить, была ли она запущена в файле скрипта или в оболочке.

mylib.sh

#!/bin/sh

MY_BASE=$0
[[ "${_NAME_OF_THIS_LIBSCRIPT:-""}" == "yes" ]] && return 0
[[ "${MY_BASE:0:1}" != "-" ]] && _NAME_OF_THIS_LIBSCRIPT=yes

function sysLOG() {
    echo $1 $_NAME_OF_THIS_LIBSCRIPT
}

test.sh

#!/bin/sh

source /tmp/mylib.sh
sysLOG 1
source /tmp/mylib.sh
sysLOG 2
source /tmp/mylib.sh
sysLOG 3

$ test.sh;echo $_NAME_OF_THIS_LIBSCRIPT
1 yes
2 yes
3 yes

$ source mylib.sh;sysLog Hey;echo $_NAME_OF_THIS_LIBSCRIPT
Hey! yes

Без [[ "${MY_BASE:0:1}" != "-" ]] &&

$ source mylib.sh;sysLog Hey;echo $_NAME_OF_THIS_LIBSCRIPT
Hey! yes
yes

Вы можете создать своего рода флаг, чтобы отследить, загружен ли он уже:

Этот пример от мастера Adrelanos:

get_colors(){
  get_colors_sourced=1
  ## Отключить цвета, если присутствуют некоторые переменные окружения.
  if test -n "${NO_COLOR:-}" || test -n "${ANSI_COLORS_DISABLED:-}"; then
    nocolor=""
    bold=""
    nobold=""
    underline=""
    nounderline=""
    red=""
    green=""
    yellow=""
    blue=""
    magenta=""
    cyan=""
    return 0
  fi

  nocolor="\033[0m"
  bold="\033[1m"
  nobold="\033[22m"
  underline="\033[4m"
  nounderline="\033[24m"
  red="\033[31m"
  green="\033[32m"
  yellow="\033[33m"
  blue="\033[34m"
  magenta="\033[35m"
  cyan="\033[36m"
}

if test "${get_colors_sourced:-}" != "1"; then
  get_colors
fi

Простое решение для запуска скриптов и других ситуаций:

test -z "$(declare -f some_function_inside_file)" >/dev/null || source "yourfile.sh" || printf '%s' 'Уже загружен'

Ответ или решение

Избегание многократной источниковой загрузки скриптов в Bash

При работе с командной оболочкой Bash на macOS, многие пользователи сталкиваются с проблемой долгой загрузки терминала из-за многократной инициализации скриптов, указанных в ~/.bash_profile. Давайте рассмотрим, как можно оптимизировать этот процесс и избежать многократной загрузки одном и том же скрипта.

Понимание процесса загрузки

При каждом открытии нового сеанса терминала, macOS выполняет команду source ~/.bash_profile, если используется стандартное приложение Terminal.app. В результате этого, каждый раз, когда вы открываете новый терминал, выполняются все команды, находящиеся в bash_profile, что может занимать время, особенно если в нем есть множество вызовов source для других скриптов и конфигурационных файлов.

Решение проблемы с медленной инициализацией

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

  1. Использование флагов для загрузки скриптов:
    Вы можете использовать переменные-флаги для отслеживания того, загружались ли скрипты ранее. Это может выглядеть следующим образом:

    # ~/.bash_profile
    if [ -z "$SCRIPTS_LOADED" ]; then
       export SCRIPTS_LOADED=1
       source ~/.script_one
       source ~/.script_two
       # Добавьте другие сценарии по мере необходимости
    fi

    Так, если ~/.bash_profile загружается повторно, скрипты не будут загружены повторно, что значительно ускорит процесс.

  2. Создание общего файла конфигурации:
    Можно создать отдельный файл конфигурации, который будет загружаться только один раз:

    # ~/.bash_profile
    if [ -f ~/.config_loaded ]; then
       source ~/.config_loaded
    else
       # Выполняем ваши скрипты
       source ~/.script_one
       echo "Конфигурация загружена" > ~/.config_loaded
    fi

Как избежать повторного источника скриптов

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

# Внутри вашего скрипта
if [[ "${_MY_SCRIPT_LOADED:-}" == "yes" ]]; then
    return 0
fi

export _MY_SCRIPT_LOADED=yes

# Ваш код здесь

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

Итоги и рекомендации

Эти стратегии помогут вам значительно сократить время загрузки нового терминала на вашем Mac. Следует помнить, что конфигурация вашего терминала – это далеко не пустяк, и правильный подход к организации загрузки скриптов может значительно улучшить ваш опыт работы с Bash. Настоятельно рекомендуется применять переменные-флаги или условия загрузки, чтобы избежать ненужных повторных загрузок.

Оцените материал
Добавить комментарий

Капча загружается...